After one year I finally found the answer: await 0
was used in order to free event loop so browser can draw frame.
Note: My explanation is verbose and has some poor grammer usages. It may be better to read MDN doc linked above.
Since JS is designed to be a single-threaded(while there exists a web worker) languaged, it has a concurrency model called event loop. Consider a following situation:
console.log('before timeout')
setTimeout(() => console.log('inside timeout'), 0)
console.log('after timeout')
Result will be:
before timeout
after timeout
inside timeout
It can be confusing at first. You might think: The timeout was set with delay of 0, thereby it would execute its callback before executing next line of code! But that's not true.
To understand the above code, let's first see how JS handle code execution. It has a storage called stack that tracks where the current function execution was originated from.
function a() {
console.log('a()')
}
a()
console.log('end')
In the above code, code outside brackets are executed first. Then, function a will be executed. At this point, the stack will look like this:
a
(Main) -> code outside every brackets
If some function calls another function the called one gets stacked on the previous one. Now the function the end and JS clears it from the top of the stack, go back to previous position, execute remaining code until it reaches the end, and so on. By utilizing stack JS can figure out where to go after current function ends.
Then what happens when we execute the setTimeout? The important thing here is that setTimeout is not a language feature but a platform feature which browser deals with. The browser waits for the given time while continuing following code execution. Then the timeout ends and the browser needs to execute its callback, but the problem is that the another piece of code might still on execution. To solve this, the browser makes callback as a task and register it in task queue. Tasks in it will be executed in sequence when the stack is empty.
This explains the odd behavior of the first code snippet: setTimeout's callback gets registered as task and it waits until stack is empty. After logging the second message main code execution ends and callback finally gets executes.
Promise is handled in similar way(but as microtask). Whether or not the right side of await is a promise, every codes that needs to be exexuted after await gets registered as microtask. The main benefit of doing so is related to the fact that browser only draw frame when the stack empty. By registering remaining code as microtask stack gets empty before the microtask gets executed, therefore browser can draw frame in that timing.
await 0
will force the above code to wait for the promise to resolve in order to execute the next code. Promises implementations introduces delays by themselves, hence this will slightly slow down the amount of executions of that function call specifically, increasing the overall performance. As you can see, in fact, this is called in theif (!instant)
, otherwise the await will be ignored. – EdsonsetTimeout
function with timeout of0
, or intoPromise.resolve().then()
method. – Winnahawait 0
is returned, the execution will take more time (look at the b() compiled function on the right textarea of the page) – Edsoninvalidate()
will prevent rendering shadow DOM simultaneously. It will try to do the work not at the same time(if it's possible). Am I wrong? – Fellatio