This commit is contained in:
Ilya Kantor 2019-04-05 09:17:26 +03:00
parent d7d1c17de9
commit 2a39ef8050
2 changed files with 27 additions and 22 deletions

View file

@ -38,11 +38,9 @@ That's why "code finished" in the example above shows first.
Promise handlers always go through that internal queue.
If there's a chain with multiple `.then/catch/finally`, then every one of them is executed asynchronously.
If there's a chain with multiple `.then/catch/finally`, then every one of them is executed asynchronously. That is, it first gets queued, and executed when the current code is complete and previously queued handlers are finished.
That is, it first gets queued, and executed when the current code is complete and previously queued handlers are finished.
What if the order matters for us? How to make `code finished` work after `promise done`?
**What if the order matters for us? How to make `code finished` work after `promise done`?**
Easy, just put it into the queue with `.then`:
@ -56,7 +54,7 @@ Now the order is as intended.
## Event loop
Browser Javascript, as well as Node.js, is based on an *event loop*.
In-browser Javascript, as well as Node.js, is based on an *event loop*.
"Event loop" is a process when the engine sleeps and waits for events, then reacts on those and sleeps again.
@ -73,7 +71,7 @@ Things happen -- the engine handles them -- and waits for more to happen (while
As you can see, there's also a queue here. A so-called "macrotask queue" (v8 term).
When an event happens, and the engine is busy, the event is enqueued.
When an event happens, while the engine is busy, its handling is enqueued.
For instance, while the engine is busy processing a network `fetch`, a user may move their mouse causing `mousemove`, and `setTimeout` may be due and so on, just as painted on the picture above.
@ -90,7 +88,7 @@ In other words, the engine first executes all microtasks, and then takes a macro
For instance, take a look:
```js run
setTimeout(() => alert("timeout"), 0);
setTimeout(() => alert("timeout"));
Promise.resolve()
.then(() => alert("promise"));
@ -122,9 +120,7 @@ Promise.resolve()
Naturally, `promise` shows up first, because `setTimeout` macrotask awaits in the less-priority macrotask queue.
**As a side effect, macrotasks are handled only when promises give the engine a "free time".**
So call have a promise chain that doesn't wait for anything, then things like `setTimeout` or event handlers can never get in the middle.
As a logical consequence, macrotasks are handled only when promises give the engine a "free time". So if we have a promise chain that doesn't wait for anything, then things like `setTimeout` or event handlers can never get in the middle.
## Unhandled rejection
@ -159,12 +155,12 @@ promise.catch(err => alert('caught'));
window.addEventListener('unhandledrejection', event => alert(event.reason));
```
Now let's say, we'll be catching the error, but after an extremely small delay:
Now let's say, we'll be catching the error, but after `setTimeout`:
```js run
let promise = Promise.reject(new Error("Promise Failed!"));
*!*
setTimeout(() => promise.catch(err => alert('caught')), 0);
setTimeout(() => promise.catch(err => alert('caught')));
*/!*
// Error: Promise Failed!
@ -173,7 +169,7 @@ window.addEventListener('unhandledrejection', event => alert(event.reason));
Now the unhandled rejction appears again. Why? Because `unhandledrejection` triggers when the microtask queue is complete. The engine examines promises and, if any of them is in "rejected" state, then the event is generated.
In the example above `setTimeout` adds the `.catch`, and it triggers too, of course it does, but later, after the event has already occured.
In the example, the `.catch` added by `setTimeout` triggers too, of course it does, but later, after `unhandledrejection` has already occured.
## Summary