I've been learning about the event loop that browsers use and how it processes macrotasks and microtasks when they are added to their respective queues.
My question is how does the event loop know that a promise has resolved so that it can then run the microtask of the then/catch/finally code?
For example say the promise is an HTTP request. The http request is sent within some function and code execution can continue synchronously. Some time later the promise resolves and the associated then code runs.
Is the HTTP request done on some other browser thread, which when it gets the result it then adds to the microtask queue that the then code can now be executed?
Related
I've observed that in the following code:
setTimeout(function(){console.log('setTimeout')});
Promise.resolve(1).then(function(){console.log('promise resolve')})
No matter how many times I execute this, the promise callback always logs before the setTimeout.
My understanding is that both callbacks are scheduled to be executed to the next tick, and I don't really understand what is going on that makes the promise always take precendence over the timeout.
Promise.resolve schedules a microtask and the setTimeout schedules a macrotask. And the microtasks are executed before running the next macrotask.
Short answer Promises have better priority than setTimeout callback function in event loop stack(or how i understand it).
Long answer watch this video. Very helpful. Hope this helps.
https://www.youtube.com/watch?v=8aGhZQkoFbQ
Thanks #MickJuice for new and updated video for event loop.
https://www.youtube.com/watch?v=cCOL7MC4Pl0
setTimeout() has a minimum delay of 4ms, so even though you didn't specify a delay in your code the timeout will still be delayed at least 4ms. Your promise's .then() is called in the meantime.
Timeouts and Promises both serve to execute code in an asynchronous way but with differences characteristics and purposes:
setTimeout
- Delays the execution of a function by specific time duration.
- Does not block the rest of the code execution (asynchronous behavior)
- They create Macrotask (browser internal operation)
Promises
- They are a wrapper to allow asynchronous execution of code(Eg: an ajax call). (Does not depend on specific time duration)
- They are especially useful to chain different async calls.
- Does not block the rest of the code execution (asynchronous behavior) at less you are using the await operator.
- They create Microtask (browser internal operation), which have priority over the Macrotask.
Recommendation
Use setTimeout when you want to delay a function execution some specific time duration and not block the rest of the code execution in the process
Use Promises:
When you want to execute some async code and to avoid the “callback hell” (yes because you can make asynchronous ajax calls without Promises but the syntax is less clear and more prone to errors)
This has to do with the event loop as defined in the Web Spec. The browser has multiple task queues for multiple types of tasks (e.g. timer tasks created through setTimeout), as well as a microtask queue (where Promise settlement gets pushed to). Whenever the browser finishes executing a task, it empties the microtask queue and executes all tasks in it, before continuing with a task from another task queue.
Therefore after the code executes (which is a task), the Promise settlement is inside of the microtask queue, and the timer task might already be inside a task queue¹. The microtask queue gets emptied and the Promise resolves. Then somewhen the timer task runs.
¹ Browsers might choose to increase timeouts a bit, and they do. A timeout will never run after 0ms in most browsers.
Timeouts and Promises serve different purposes.
setTimeout delays the execution of the code block by a specific time duration. Promises are an interface to allow async execution of code.
A promise allows code to continue executing while you wait for another action to complete. Usually this is a network call. So anything in your then() call will be executed once the network call (or whatever the promise is waiting for) is completed. The time difference between the start of the promise and the resolution of the promise entirely depends on what the promise is executing, and can change with every execution.
The reason the promise is executing before your timeout is that the promise isn't actually waiting for anything so it resolved right away.
I read a lot of articles about promises. I know that promise executions are microtasks for task queue, async code executions are tasks for task queue. How does it happen in promises that after asynchronous code works synchronous code (i.e. after some fetch we can write synchronous code in .then block)?
I guess that all code inside promises use callstack (if sync code inside Promise body) or task queue (if async code inside Promise body). I saw a lot of examples with callstack, Web API and task queue with setTimeout code but how it works with promises I can only assume.
Can you show on my examples what happens with callstack, Web API and task queue, please?
First example:
const promiseWithAsyncBody = new Promise(resolve=>
setTimeout(()=> resolve('resolved'), 0));
promiseWithAsyncBody.then(msg=> console.log(msg));
I guess that promise body gets into task queue, then it gets into in callstack, when code come into setTimeout, setTimeout gets into WebAPI and immediately gets into task queue but at the same moment .then block gets into the task queue. After that triggers setTimeout and only after setTimeout triggering .then block.
Second example:
const promiseWithSyncBody = new Promise(resolve=> resolve('resolved'));
promiseWithAsyncBody.then(msg=> console.log(msg));
I guess that promise body executes in callstack and till that executes .then block gets into the task queue. When callstack is empty, .then block executes.
Am I right? Explain in more details who knows please. Thank you!
When you create a promise
const promise = new Promise(/*executorFunction*/ (resolve, reject) =>
{/* executor function body */}
)
the body of executorFuncton is being executed right away.
Inside the body of executor function you may or may not call some asynchronous api's.
After a promise is just created it is in "pending" state.
If inside of executor function resolve callback is called, the promise's state becomes "fulfilled" (or it may became "rejected" if reject callback is called).
And only after the promise become fulfilled a microtask is crated (which wraps a callback you've provided in then() call) and pushed into microtask queue by browser.
The observable difference between task queue and microtask is that tasks in microtask queue always
run before tasks in task queue. And that's the only clear info about microtask and task queue I found on the internet when I was interested in this topic too.
I am understanding how the js engine handles promises then I got this great article https://medium.com/#jitubutwal144/javascript-how-is-callback-execution-strategy-for-promises-different-than-dom-events-callback-73c0e9e203b1.
This made me very much clear.
But If we make an HTTP request inside the promise then when js see that promise object which contains Http request it adds its callback in the microtask queue and js call stack starts executing promise. It saw HTTP request and send's it to browser to make it. Now the browser is completed with it and add's http callback to task queue which calls resolve, request. According to its js engine first picks micro task but it cannot do anything with a microtask because its resultant callback is in the task queue. I am confused about how the js engine will handle it.
Can anyone please help
I've observed that in the following code:
setTimeout(function(){console.log('setTimeout')});
Promise.resolve(1).then(function(){console.log('promise resolve')})
No matter how many times I execute this, the promise callback always logs before the setTimeout.
My understanding is that both callbacks are scheduled to be executed to the next tick, and I don't really understand what is going on that makes the promise always take precendence over the timeout.
Promise.resolve schedules a microtask and the setTimeout schedules a macrotask. And the microtasks are executed before running the next macrotask.
Short answer Promises have better priority than setTimeout callback function in event loop stack(or how i understand it).
Long answer watch this video. Very helpful. Hope this helps.
https://www.youtube.com/watch?v=8aGhZQkoFbQ
Thanks #MickJuice for new and updated video for event loop.
https://www.youtube.com/watch?v=cCOL7MC4Pl0
setTimeout() has a minimum delay of 4ms, so even though you didn't specify a delay in your code the timeout will still be delayed at least 4ms. Your promise's .then() is called in the meantime.
Timeouts and Promises both serve to execute code in an asynchronous way but with differences characteristics and purposes:
setTimeout
- Delays the execution of a function by specific time duration.
- Does not block the rest of the code execution (asynchronous behavior)
- They create Macrotask (browser internal operation)
Promises
- They are a wrapper to allow asynchronous execution of code(Eg: an ajax call). (Does not depend on specific time duration)
- They are especially useful to chain different async calls.
- Does not block the rest of the code execution (asynchronous behavior) at less you are using the await operator.
- They create Microtask (browser internal operation), which have priority over the Macrotask.
Recommendation
Use setTimeout when you want to delay a function execution some specific time duration and not block the rest of the code execution in the process
Use Promises:
When you want to execute some async code and to avoid the “callback hell” (yes because you can make asynchronous ajax calls without Promises but the syntax is less clear and more prone to errors)
This has to do with the event loop as defined in the Web Spec. The browser has multiple task queues for multiple types of tasks (e.g. timer tasks created through setTimeout), as well as a microtask queue (where Promise settlement gets pushed to). Whenever the browser finishes executing a task, it empties the microtask queue and executes all tasks in it, before continuing with a task from another task queue.
Therefore after the code executes (which is a task), the Promise settlement is inside of the microtask queue, and the timer task might already be inside a task queue¹. The microtask queue gets emptied and the Promise resolves. Then somewhen the timer task runs.
¹ Browsers might choose to increase timeouts a bit, and they do. A timeout will never run after 0ms in most browsers.
Timeouts and Promises serve different purposes.
setTimeout delays the execution of the code block by a specific time duration. Promises are an interface to allow async execution of code.
A promise allows code to continue executing while you wait for another action to complete. Usually this is a network call. So anything in your then() call will be executed once the network call (or whatever the promise is waiting for) is completed. The time difference between the start of the promise and the resolution of the promise entirely depends on what the promise is executing, and can change with every execution.
The reason the promise is executing before your timeout is that the promise isn't actually waiting for anything so it resolved right away.
I've observed that in the following code:
setTimeout(function(){console.log('setTimeout')});
Promise.resolve(1).then(function(){console.log('promise resolve')})
No matter how many times I execute this, the promise callback always logs before the setTimeout.
My understanding is that both callbacks are scheduled to be executed to the next tick, and I don't really understand what is going on that makes the promise always take precendence over the timeout.
Promise.resolve schedules a microtask and the setTimeout schedules a macrotask. And the microtasks are executed before running the next macrotask.
Short answer Promises have better priority than setTimeout callback function in event loop stack(or how i understand it).
Long answer watch this video. Very helpful. Hope this helps.
https://www.youtube.com/watch?v=8aGhZQkoFbQ
Thanks #MickJuice for new and updated video for event loop.
https://www.youtube.com/watch?v=cCOL7MC4Pl0
setTimeout() has a minimum delay of 4ms, so even though you didn't specify a delay in your code the timeout will still be delayed at least 4ms. Your promise's .then() is called in the meantime.
Timeouts and Promises both serve to execute code in an asynchronous way but with differences characteristics and purposes:
setTimeout
- Delays the execution of a function by specific time duration.
- Does not block the rest of the code execution (asynchronous behavior)
- They create Macrotask (browser internal operation)
Promises
- They are a wrapper to allow asynchronous execution of code(Eg: an ajax call). (Does not depend on specific time duration)
- They are especially useful to chain different async calls.
- Does not block the rest of the code execution (asynchronous behavior) at less you are using the await operator.
- They create Microtask (browser internal operation), which have priority over the Macrotask.
Recommendation
Use setTimeout when you want to delay a function execution some specific time duration and not block the rest of the code execution in the process
Use Promises:
When you want to execute some async code and to avoid the “callback hell” (yes because you can make asynchronous ajax calls without Promises but the syntax is less clear and more prone to errors)
This has to do with the event loop as defined in the Web Spec. The browser has multiple task queues for multiple types of tasks (e.g. timer tasks created through setTimeout), as well as a microtask queue (where Promise settlement gets pushed to). Whenever the browser finishes executing a task, it empties the microtask queue and executes all tasks in it, before continuing with a task from another task queue.
Therefore after the code executes (which is a task), the Promise settlement is inside of the microtask queue, and the timer task might already be inside a task queue¹. The microtask queue gets emptied and the Promise resolves. Then somewhen the timer task runs.
¹ Browsers might choose to increase timeouts a bit, and they do. A timeout will never run after 0ms in most browsers.
Timeouts and Promises serve different purposes.
setTimeout delays the execution of the code block by a specific time duration. Promises are an interface to allow async execution of code.
A promise allows code to continue executing while you wait for another action to complete. Usually this is a network call. So anything in your then() call will be executed once the network call (or whatever the promise is waiting for) is completed. The time difference between the start of the promise and the resolution of the promise entirely depends on what the promise is executing, and can change with every execution.
The reason the promise is executing before your timeout is that the promise isn't actually waiting for anything so it resolved right away.