idnexeeddb draft, microqueue fixes

This commit is contained in:
Ilya Kantor 2019-03-11 14:14:41 +03:00
parent 364e707b2a
commit 32bf3fdb08
5 changed files with 627 additions and 18 deletions

View file

@ -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.

View file

@ -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.