Hacker News new | past | comments | ask | show | jobs | submit login
Explaining the browser's event loop, tasks, and microtasks (jakearchibald.com)
152 points by jaffathecake on Aug 17, 2015 | hide | past | favorite | 21 comments



I've been trying to explain the JS event loop to a couple of our interns recently and this is an amazing illustration of the basics and the not-so-basics. Thanks!


I'm quite surprised that the output of the examples is even supposed to be deterministic!


Only because both the timeout and promises are pre-resolved. They both immediately "complete" their tasks, so the callbacks are immediately queued. That means you're measuring event loop queuing order, and ignoring execution time.


That's a terrifying read for anyone doing complex javascript in a browser.

Or just don't use Promises ;-)


Terrifying because there are cases with poor interoperability, or terrifying because the metal model is non-trivial?

If you mean the former, that's certainly a pain point on the web (although it's worth noting that some of the specific issues Jake mentioned are already fixed in at least Firefox nightly). For that reason tests like these are being tested in the web-platform-tests project [1], which is part of the Test The Web Forward initiative [2] aiming to create a common, cross-browser testsuite which all vendors can run in automation so that they are able to detect this kind of issue during development and avoid compat-affecting regressions of the kind seen here. Firefox runs (almost) all the web-platform-tests in its CI system already, Chrome runs a subset and are looking to add more, Servo runs the cubset corresponding to the features it supports, and what Microsoft and Apple do is a mystery to me. I believe the Jake is going to look at submitting his testcases, and I hope that in the future web authors will see the value in investing in their platform by submitting tests and bug reports when they run into interop difficulties.

If you just mean that the lowest levels of the web-platform are quite complicated then yes, but it's not that surprising (and the things that are complicated to implement are not necessarily hard to use; document.write is a tremendous pain to understand in detail and implement, but people nevertheless use it with reckless abandon).

[1] https://github.com/w3c/web-platform-tests [2] http://testthewebforward.org/


Do people use `document.write` with reckless abandon? I haven't used it in about a decade!


It's weirdly prevalent in ads apparently. Like, to the point that you get a pretty ad-free web by just shipping a browser without document.write. Actually, that doesn't sound like such a bad idea...


Yeah, stuff like https://code.google.com/p/chromium/issues/detail?id=457409 is pretty scary:

FWIW, neither FF nor Chrome - nor the spec - have intentional behavior here; the implementations and spec predate microtasks, so the behavior "falls out" differently in different places.


Currently working on a list of "important things they never tell you as a web developer" - this is being added near the top. Thanks for this and fighting the good fight with ServiceWorker, Jake.


Pale Moon, x64:

    Test 1: script start; script end; promise1; promise2; setTimeout

    Test 2: click promise mutate click promise mutate timeout timeout

    Test 3: click click promise promise mutate timeout timeout
Interesting that this is so far from Firefox's responses even though it's a FF fork.


Fantastic, thank you for taking the time to digest a complicated spec and turn it into a nice walkthrough!


Really great article, spending your weekend making the animated step-by-step diagrams was worth it!

The fact that browsers don't get this stuff right by now is pretty worrying. Makes it difficult to imagine the web being the platform of the future and complex applications being built atop it.


In fact, the first example gives different results between different runs (clicks) on iOS 8.4.1 Mobile Safari, even without reloading the page.


I think this is something that nodejs should include by default (multithreaded workers).


That's not what the post is about, it covers actions scheduled on a single thread. However, you can do multi-process, therefore mutli-thread with node, using https://nodejs.org/api/child_process.html#child_process_chil... or https://nodejs.org/api/cluster.html


I know it is not related with NodeJS but I would like to have it with Node. The cluster model is inefficient since it uses processes instead of threads. One unofficial answer for NodeJS is https://www.npmjs.com/package/webworker-threads


great article and a really fun read!


Does the spec explicitly tells about how to time tasks vs microtasks? I was under the impression that it was up to the implementation and not relevant.

To add something more, I would really like to see an example where this actually ruins a program execution.

Edit: And this is wrong because... ?


These questions are already answered in the post.

Yes, both microtask and task execution is specced by html. Using a task rather than a microtask costs performance by the time it takes to do other between-task things such as rendering. There was an opinion that promises were slow that was really only down to poor callback scheduling.


Ok, thanks. Haven't read the spec, that's why I was asking.

>However, the general consensus is that promises should be part of the microtask queue, and for good reason.

That's the only bit I found in the post regarding that. Didn't sound like 'it's in the spec' to me.

Regarding the example, (I'm gonna sound like the SO posters that I hate but) there are other appropiate places where you should hook up that callback. If the one you chose does not play well with Promises yet (because you want to access an object thats at the end of its lifetime and not guaranteed to exist), then ¯\_(ツ)_/¯.

I asked for an example where the program breaks because I thought that if you queue up things 'for later dispatch' you shouldn't be worriyng about the order where they dispatch. If you're actually worried, then chain them together with the classic callback stuff.

But, I'm not demeaning your post (I see you're the author), it was really good. The main issue is see is (as you stated in your comment) that Promises as microtasks would increase their performance. It is a shame, however, that we as developers are not able to queue microtasks directly (like when using setImmediate, process.nextTick) :(


The spec defines the execution of tasks vs microtasks tightly, the bit that's less clear is how ECMAScript promise jobs interact with microtasks - the consensus is they're in the same queue, but it isn't explicit.

I agree that we should have an API to queue microtasks, although as soon as promises use microtasks, Promise.resolve().then(func) becomes that API. Some promise polyfills also use mutation events to queue microtasks.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: