I know this is 7 years old question, but:
Answer:
- The Promise block is synchronous
- The Promise callback blocks (resolve, reject) are synchronous
- The callback
call
(not the block itself) can be asynchronous if the Promise block uses a setTimeout block
So, to answer the direct question that Jane Wayne was doing, yes, using the setTimeout block will make the Promise block non-blocking.
Explanation:
Javascript is synchronous, it has just 1 thread. The Javascript engine uses a stack (Call Stack
) to execute all the stuff (LIFO
).
Side to side, you have the Web APIs, that are part of the Browser. There, for example, you can find setTimeout
as part of the Window
object.
The communication between both worlds is done by using 2 queues (Microtask and Macrotask queues, that are FIFO
) managed by the Event Loop
, that it is a process that runs constantly.
Event Loop, Microtask and Macrotask queues
The execution goes like:
- Execute all the script using the Call Stack
- The
Event Loop
checks all the time if the Call Stack
is empty
- If the
Event Loop
finds that the Call Stack
is empty, then starts passing callbacks from the Microtask queue
, if any, to the Call Stack
- Once the
Microtask queue
is empty, the Event Loop
does the same for the Macrotask queue
So, getting into the Promise
world.
- The Promise block is executed synchronous
- Inside the
Promise
block, you can have something that it is executed outside the Javascript engine (a setTimeout
block, for example), that is what we call asynchronous, because it runs outside the Javascript thread.
- The execution of the callbacks (
resolve
and reject
) of the Promise is what you can consider asynchronous, but the block itself it is executed synchronous
So, if inside the Promise block you do not have any asynchronous block, the Promise will block your execution.
And, if in the callback part you do not have any asynchronous block, the Promise will block your execution.
Example:
console.log(`Start of file`)
const fourSeconds = 4000
// This will not block the execution
// This will go to the Macrotask queue
// Microtask queue has preference over it, so all the Promises not using setTimeout
setTimeout(() => {
console.log(`Callback 1`)
})
// This will block the execution because the Promise block is synchronous
// But the result will be executed after all the Call Stack
// This will be the first Microtask printed
new Promise((resolve, reject) => {
let start = Date.now()
while (Date.now() - start <= fourSeconds) { }
resolve(`Promise block resolved`)
}).then(result => console.log(result))
// This will not block the execution
// This will go into the Macrotask queue because of setTimeout
// Will block all the Macrotasks queued after it
// In this case will block the Macrotask "Callback 2" printing
new Promise((resolve, reject) => {
setTimeout(() => resolve(`Promise callback block resolved`))
}).then(result => {
let start = Date.now()
while (Date.now() - start <= fourSeconds) { }
console.log(result)
})
// This will not block the execution
// This will go to the Macrotask queue
// Microtask queue has preference over it
// Also the previous Macrotasks has preference over it, so this will be the last thing to be executed
setTimeout(() => {
console.log(`Callback 2`)
})
// This will not block the execution
// It will go to the Microtask queue having preference over the setTimeout
// Also the previous Microtasks has preference over it
Promise.resolve(`Simply resolved`).then(result => console.log(result))
console.log(`End of file`)
/*
Output:
Start of file
[... execution blocked 4 seconds ...]
End of file
Promise block resolved
Simply resolved
Callback 1
[... execution blocked 4 seconds ...]
Promise callback block resolved
Callback 2
*/