Skip to content

Instantly share code, notes, and snippets.

@Sauloxd
Forked from jesstelford/README.md
Created July 25, 2017 15:21
Show Gist options
  • Save Sauloxd/1d6ff312f89d97b80f187b59c84f3ab6 to your computer and use it in GitHub Desktop.
Save Sauloxd/1d6ff312f89d97b80f187b59c84f3ab6 to your computer and use it in GitHub Desktop.
Starving the Event Loop with Microtasks

Starving the Event Loop with microtasks

Sparked from this twitter conversation when talking about doing fast async rendering of declarative UIs in Preact

These examples show how it's possible to starve the main event loop with microtasks (because the microtask queue is emptied at the end of every item in the event loop queue). Note that these are contrived examples, but can be reflective of situations where Promises are incorrectly expected to yield to the event loop "because they're async".

  • setTimeout-only.js is there to form a baseline
  • chained-promises.js shows the event loop being starved when many microtasks are queued at once
  • promises-returning-promises.js shows chained .then() calls starving the event loop
  • nested-chained-promises.js shows nested .then() calls starving the event loop
  • promise-all.js shows Promise.all() also suffers from this

For more on microtasks and the event loop, check out Jake Archibald's article "Tasks, microtasks, queues and schedules"

let start = performance.now()
setTimeout((_=>console.log(performance.now() - start)), 0)
let p = Promise.resolve(1)
for(let i = 100000; i; i--) {
p = p.then(_ => 1);
}
// Invokes overhead of creating new Promise objects until the start of each microtask.
let start = performance.now()
setTimeout((_=>console.log(performance.now() - start)), 0)
let count = 100000
function createNewPromise() {
return Promise.resolve(1).then(_ => {
if (count) {
createNewPromise()
count--;
}
})
}
Promise.resolve(1).then(createNewPromise);
// Running parallel promises all occur in the single turn of the micro task queue
let start = performance.now()
setTimeout((_=>console.log(performance.now() - start)), 0)
let promises = []
for(let i = 100000; i; i--) {
promises.push(Promise.resolve(1));
}
Promise.all(promises)
// Invokes overhead of creating new Promise objects
let start = performance.now()
setTimeout((_=>console.log(performance.now() - start)), 0)
let p = Promise.resolve(1);
for(let i = 100000; i; i--) {
p = p.then(_ => Promise.resolve(1));
}
let start = performance.now()
setTimeout((_=>console.log(performance.now() - start)), 0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment