idnexeeddb draft, microqueue fixes
This commit is contained in:
parent
364e707b2a
commit
32bf3fdb08
5 changed files with 627 additions and 18 deletions
|
@ -21,7 +21,7 @@ What's going on?
|
|||
|
||||
# Internal queue
|
||||
|
||||
Asynchronous tasks need proper management. For that, the standard specifies an internal queue of "Promise Jobs".
|
||||
Asynchronous tasks need proper management. For that, the standard specifies an internal queue of "Promise Jobs", sometimes called "microtask queue" (v8 term).
|
||||
|
||||
As said in the [specification](https://tc39.github.io/ecma262/#sec-jobs-and-job-queues):
|
||||
|
||||
|
@ -40,7 +40,7 @@ If there's a chain with multiple `.then/catch/finally`, then every one of them i
|
|||
|
||||
What if the order matters for us, and we want to see `code finished` after `promise done`?
|
||||
|
||||
Easy, just put it into the queue:
|
||||
Easy, just put it into the queue with `.then`:
|
||||
|
||||
```js run
|
||||
new Promise(resolve => resolve("promise done!"))
|
||||
|
@ -52,7 +52,7 @@ Now the order is as intended.
|
|||
|
||||
## Higher-order queues
|
||||
|
||||
There are other action queues, depending on the environment.
|
||||
There are other action queues, depending on the environment, often called "macrotasks" (as opposed to promise "microtasks").
|
||||
|
||||
For instance, `setTimeout` enqueues an action when the time comes, or even right now if the timeout is zero:
|
||||
|
||||
|
@ -61,10 +61,10 @@ setTimeout(handler, 0); // handler is queued for immediate execution.
|
|||
```
|
||||
|
||||
Other examples:
|
||||
- Pending events (like mouse movements in the browser)
|
||||
- Network operations that may take time, or may finish immediately if the result is cached.
|
||||
- Events that wait to be handled (like mouse moves in the browser)
|
||||
- Completed network operations, pending to be handled. These, just like `setTimeout`, may take time, or finish immediately if the result is cached.
|
||||
|
||||
**Promise queue has higher priority than environment-related queues.**
|
||||
**Promise queue has a higher priority than environment-related queues.**
|
||||
|
||||
For instance, take a look:
|
||||
|
||||
|
@ -81,7 +81,7 @@ alert("code");
|
|||
2. `promise` shows second, because `.then` passes through the promise queue, runs after the current code.
|
||||
3. `timeout` shows last, because environment-specific queue has lower priority.
|
||||
|
||||
That's also true for more complex calls, e.g if we schedule an immediate `setTimeout` call inside the promise, then it also executes last:
|
||||
That's also true for nested calls, e.g if we schedule an immediate `setTimeout` call inside the promise:
|
||||
|
||||
```js run
|
||||
new Promise(resolve => {
|
||||
|
@ -90,20 +90,20 @@ new Promise(resolve => {
|
|||
}).then(alert);
|
||||
```
|
||||
|
||||
Here also `promise` triggers first, because promise actions have higher priority.
|
||||
Here also `promise` triggers first, because promise handling have higher priority.
|
||||
|
||||
## Summary
|
||||
|
||||
Promise handling is always async, as all promise actions pass through the internal "promise jobs" queue.
|
||||
Promise handling is always async, as all promise actions pass through the internal "promise jobs" queue, also called "microtask queue" (v8 term).
|
||||
|
||||
**So, `.then/catch/finally` is called after the current code is finished.**
|
||||
|
||||
If we need to guarantee that a piece of code is executed after `.then/catch/finally`, it's best to add it into a chained `.then` call.
|
||||
|
||||
Other environments may have their own async actions, like events, network-related calls, filesystem tasks, and `setTimeout`-scheduled calls.
|
||||
Other environments may have their own async actions, like events, network-related calls, filesystem tasks, and `setTimeout`-scheduled calls. These are also called "macrotasks" (v8 term).
|
||||
|
||||
**Environment-specific async actions happen after the code is finished *and* after the promise queue is empty.**
|
||||
|
||||
In other words, they have lower priority.
|
||||
|
||||
So we know for sure a promise chain goes as far as possible first. It may finish or hang waiting for something outside of the promise queue, and only then an event-related handler or `setTimeout` may trigger.
|
||||
So the order is: regular code, then promise handling, then everything else.
|
||||
|
|
|
@ -281,11 +281,31 @@ In case of an error, it propagates as usual: from the failed promise to `Promise
|
|||
|
||||
````
|
||||
|
||||
## Timiing: async/await and higher-level actions
|
||||
## Microtask queue: await and higher-level actions [#microtask-queue]
|
||||
|
||||
Some async stuff is more asynchronous than the other.
|
||||
TODO
|
||||
|
||||
For instance, `setTimeout(handler, 0)` is async, and `let x = await f()` is async. What triggers first?
|
||||
|
||||
In the browser, or other environments we have two types of async actions:
|
||||
1. `async/await`
|
||||
2. `setTimeout` calls that are to execute, pending events
|
||||
|
||||
|
||||
`Async/await` is based on promises, so it uses the promise queue internally, so-called "microtask queue".
|
||||
|
||||
When a promise is ready, it's handling is put to a special internal queue, and processed when Javascript has finished with the current code.
|
||||
|
||||
That's explained in detail in the chapter <info:promise-queue>. Promise `.then/catch/finally` handlers get queued, and then executed when the currently running code is complete.
|
||||
|
||||
If we use `async/await`, things are much simpler than with promises. No chaining. So we don't care much about that internal queue.
|
||||
|
||||
But there's an important side effect that we should understand: some async stuff is more asynchronous than the other.
|
||||
|
||||
For instance, we have:
|
||||
- `setTimeout(handler, 0)`, that should run `handler` with zero delay.
|
||||
- `let x = await f()`, function `f()` is async, but returns immediateley.
|
||||
|
||||
Which one runs first if `await` is *below* `setTimeout` in the code?
|
||||
|
||||
```js run
|
||||
async function f() {
|
||||
|
@ -293,19 +313,22 @@ async function f() {
|
|||
}
|
||||
|
||||
(async () => {
|
||||
setTimeout(() => alert('timeout'), 0);
|
||||
setTimeout(() => alert('timeout finished'), 0);
|
||||
|
||||
await f();
|
||||
|
||||
alert('await');
|
||||
alert('await finished');
|
||||
})();
|
||||
```
|
||||
|
||||
There's no ambiguity here: `await` always finishes first.
|
||||
|
||||
Remember promise queue from the chapter <info:promise-queue>? Promise `.then/catch/finally` handlers get queued, and then executed when the currently running code is complete. By specification, the promise queue has higher priority than environment-specific handlers.
|
||||
|
||||
`Async/await` is based on promises, so it uses the same promise queue internally.
|
||||
|
||||
Internally, there`setTimeout` and event handlers are also processed in a queue
|
||||
|
||||
|
||||
By specification, the promise queue has higher priority than environment-specific handlers.
|
||||
|
||||
So `await` is guaranteed to work before any `setTimeout` or other event handlers. That's actually quite essential, as we know that our async/await code flow will never be interrupted by other handlers or events.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue