Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: expand on promises and async_hooks #18540

Merged
merged 1 commit into from
Feb 5, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions doc/api/async_hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,9 @@ const server = net.createServer(function onConnection(conn) {
});
```

Note that promise contexts may not get precise executionAsyncIds by default.
See the section on [promise execution tracking][].

#### `async_hooks.triggerAsyncId()`

* Returns: {number} The ID of the resource responsible for calling the callback
Expand All @@ -531,6 +534,57 @@ const server = net.createServer((conn) => {
});
```

Note that promise contexts may not get valid triggerAsyncIds by default. See
the section on [promise execution tracking][].

## Promise execution tracking

By default, promise executions are not assigned asyncIds due to the relatively
expensive nature of the [promise introspection API][PromiseHooks] provided by
V8. This means that programs using promises or `async`/`await` will not get
correct execution and trigger ids for promise callback contexts by default.

Here's an example:

```js
const ah = require('async_hooks');
Promise.resolve(1729).then(() => {
console.log(`eid ${ah.executionAsyncId()} tid ${ah.triggerAsyncId()}`);
});
// produces:
// eid 1 tid 0
```

Observe that the `then` callback claims to have executed in the context of the
outer scope even though there was an asynchronous hop involved. Also note that
the triggerAsyncId value is 0, which means that we are missing context about the
resource that caused (triggered) the `then` callback to be executed.

Installing async hooks via `async_hooks.createHook` enables promise execution
tracking. Example:

```js
const ah = require('async_hooks');
ah.createHook({ init() {} }).enable(); // forces PromiseHooks to be enabled.
Promise.resolve(1729).then(() => {
console.log(`eid ${ah.executionAsyncId()} tid ${ah.triggerAsyncId()}`);
});
// produces:
// eid 7 tid 6
```

In this example, adding any actual hook function enabled the tracking of
promises. There are two promises in the example above; the promise created by
`Promise.resolve()` and the promise returned by the call to `then`. In the
example above, the first promise got the asyncId 6 and the latter got asyncId 7.
During the execution of the `then` callback, we are executing in the context of
promise with asyncId 7. This promise was triggered by async resource 6.

Another subtlety with promises is that `before` and `after` callbacks are run
only on chained promises. That means promises not created by `then`/`catch` will
not have the `before` and `after` callbacks fired on them. For more details see
the details of the V8 [PromiseHooks][] API.

## JavaScript Embedder API

Library developers that handle their own asynchronous resources performing tasks
Expand Down Expand Up @@ -655,3 +709,5 @@ constructor.
[`destroy` callback]: #async_hooks_destroy_asyncid
[`init` callback]: #async_hooks_init_asyncid_type_triggerasyncid_resource
[Hook Callbacks]: #async_hooks_hook_callbacks
[PromiseHooks]: https://docs.google.com/document/d/1rda3yKGHimKIhg5YeoAmCOtyURgsbTH_qaYR79FELlk
[promise execution tracking]: #async_hooks_promise_execution_tracking