
Explaining the browser's event loop, tasks, and microtasks - jaffathecake
https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
======
azundo
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!

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

~~~
jinushaun
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.

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

Or just don't use Promises ;-)

~~~
jgraham
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](https://github.com/w3c/web-
platform-tests) [2]
[http://testthewebforward.org/](http://testthewebforward.org/)

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

~~~
stupidcar
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...

------
dccoolgai
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.

------
TheLoneWolfling
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.

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

------
nathankleyn
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.

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

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

~~~
jaffathecake
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...](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)
or [https://nodejs.org/api/cluster.html](https://nodejs.org/api/cluster.html)

~~~
wslh
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](https://www.npmjs.com/package/webworker-threads)

------
anotherangrydev
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... ?

~~~
jaffathecake
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.

~~~
anotherangrydev
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) :(

~~~
jaffathecake
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.

------
stefs
great article and a really fun read!

