6 ms·
Explaining the browser's event loop, tasks, and microtasks
- bigethan 11y agoThat's a terrifying read for anyone doing complex javascript in a browser. Or just don't use Promises ;-)
- jgraham 11y agoTerrifying 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 11y agoDo people use `document.write` with reckless abandon? I haven't used it in about a decade!
- stupidcar 11y agoIt'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...
- streptomycin 11y agoYeah, stuff like https://code.google.com/p/chromium/issues/detail?id=457409 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.
- jastanton 11y agoFantastic, thank you for taking the time to digest a complicated spec and turn it into a nice walkthrough!
- azundo 11y agoI'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!
- stefs 11y agogreat article and a really fun read!
- Cakez0r 11y agoI'm quite surprised that the output of the examples is even supposed to be deterministic!
- jinushaun 11y agoOnly 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.
- nathankleyn 11y agoReally 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.
- dccoolgai 11y agoCurrently 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.
- 0x0 11y agoIn fact, the first example gives different results between different runs (clicks) on iOS 8.4.1 Mobile Safari, even without reloading the page.
- anotherangrydev 11y agoDoes 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 11y agoThese 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 11y agoOk, 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 11y agoThe 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.
- wslh 11y agoI think this is something that nodejs should include by default (multithreaded workers).
- jaffathecake 11y agoThat'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_child_process_fork_modulepath_args_options https://nodejs.org/api/child_process.html#child_process_chil... or https://nodejs.org/api/cluster.html https://nodejs.org/api/cluster.html
- wslh 11y agoI 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
- TheLoneWolfling 11y agoPale 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.