From 05e702d9f16f6808e83f6a47cfa4294dea3f7343 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sun, 4 Feb 2018 16:30:04 +0100 Subject: [PATCH 1/9] doc: fix `REPLACEME` in changelog PR URLs PR-URL: https://github.com/nodejs/node/pull/18561 Reviewed-By: Colin Ihrig Reviewed-By: Jon Moss --- doc/api/assert.md | 8 ++++---- doc/api/console.md | 2 +- doc/api/util.md | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/api/assert.md b/doc/api/assert.md index 7bade14184c..0e5f4442056 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -18,7 +18,7 @@ For more information about the used equality comparisons see added: REPLACEME changes: - version: REPLACEME - pr-url: https://github.com/nodejs/node/pull/REPLACEME + pr-url: https://github.com/nodejs/node/pull/17615 description: Added error diffs to the strict mode - version: REPLACEME pr-url: https://github.com/nodejs/node/pull/17002 @@ -445,7 +445,7 @@ See below for further details. added: v0.1.21 changes: - version: REPLACEME - pr-url: https://github.com/nodejs/node/pull/REPLACEME + pr-url: https://github.com/nodejs/node/pull/18418 description: Calling `assert.fail` with more than one argument is deprecated and emits a warning. --> @@ -728,7 +728,7 @@ parameter is an instance of an [`Error`][] then it will be thrown instead of the added: v0.1.21 changes: - version: REPLACEME - pr-url: https://github.com/nodejs/node/pull/REPLACEME + pr-url: https://github.com/nodejs/node/pull/18319 description: assert.ok() (no arguments) will now use a predefined error msg. --> * `value` {any} @@ -834,7 +834,7 @@ instead of the `AssertionError`. added: v0.1.21 changes: - version: REPLACEME - pr-url: https://github.com/nodejs/node/pull/REPLACEME + pr-url: https://github.com/nodejs/node/pull/17584 description: The `error` parameter can now be an object as well. - version: v4.2.0 pr-url: https://github.com/nodejs/node/pull/3276 diff --git a/doc/api/console.md b/doc/api/console.md index 68cab5b68f3..864560f8c5e 100644 --- a/doc/api/console.md +++ b/doc/api/console.md @@ -108,7 +108,7 @@ new Console(process.stdout, process.stderr); added: v0.1.101 changes: - version: REPLACEME - pr-url: https://github.com/nodejs/node/pull/REPLACEME + pr-url: https://github.com/nodejs/node/pull/17706 description: The implementation is now spec compliant and does not throw anymore. --> diff --git a/doc/api/util.md b/doc/api/util.md index c9ce952af38..fdf6ed69bc9 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -352,7 +352,7 @@ changes: pr-url: https://github.com/nodejs/node/pull/17907 description: The `depth` default changed to Infinity. - version: REPLACEME - pr-url: https://github.com/nodejs/node/pull/REPLACEME + pr-url: https://github.com/nodejs/node/pull/17576 description: The `compact` option is supported now. - version: v6.6.0 pr-url: https://github.com/nodejs/node/pull/8174 From b0f114ddb08a289dcef4a2ec68a598d31fc36f0c Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Thu, 1 Feb 2018 09:44:27 -0600 Subject: [PATCH 2/9] loader: fix up #18394 This commit fixes up some issues in #18394. * Switch vm.Module internals to use the new link method properly * Fix bug with ModuleWrap::Link * Add tests for ModuleWrap::Link PR-URL: https://github.com/nodejs/node/pull/18509 Fixes: https://github.com/nodejs/node/issues/18249 Refs: https://github.com/nodejs/node/pull/18394 Reviewed-By: Tiancheng "Timothy" Gu --- lib/internal/loader/ModuleWrap.js | 5 +++ lib/internal/vm/Module.js | 36 +++++++++++----------- node.gyp | 1 + src/module_wrap.cc | 2 +- test/parallel/test-internal-module-wrap.js | 29 +++++++++++++++++ 5 files changed, 54 insertions(+), 19 deletions(-) create mode 100644 lib/internal/loader/ModuleWrap.js create mode 100644 test/parallel/test-internal-module-wrap.js diff --git a/lib/internal/loader/ModuleWrap.js b/lib/internal/loader/ModuleWrap.js new file mode 100644 index 00000000000..b2b11daead7 --- /dev/null +++ b/lib/internal/loader/ModuleWrap.js @@ -0,0 +1,5 @@ +'use strict'; + +// exposes ModuleWrap for testing + +module.exports = internalBinding('module_wrap').ModuleWrap; diff --git a/lib/internal/vm/Module.js b/lib/internal/vm/Module.js index 2f139d8b260..a8fb7303aec 100644 --- a/lib/internal/vm/Module.js +++ b/lib/internal/vm/Module.js @@ -8,6 +8,7 @@ const { getConstructorOf, customInspectSymbol, } = require('internal/util'); +const { SafePromise } = require('internal/safe_globals'); const { ModuleWrap, @@ -131,27 +132,26 @@ class Module { const wrap = wrapMap.get(this); if (wrap.getStatus() !== kUninstantiated) throw new errors.Error('ERR_VM_MODULE_STATUS', 'must be uninstantiated'); + linkingStatusMap.set(this, 'linking'); - const promises = []; - wrap.link((specifier) => { - const p = (async () => { - const m = await linker(specifier, this); - if (!m || !wrapMap.has(m)) - throw new errors.Error('ERR_VM_MODULE_NOT_MODULE'); - if (m.context !== this.context) - throw new errors.Error('ERR_VM_MODULE_DIFFERENT_CONTEXT'); - const childLinkingStatus = linkingStatusMap.get(m); - if (childLinkingStatus === 'errored') - throw new errors.Error('ERR_VM_MODULE_LINKING_ERRORED'); - if (childLinkingStatus === 'unlinked') - await m.link(linker); - return wrapMap.get(m); - })(); - promises.push(p); - return p; + + const promises = wrap.link(async (specifier) => { + const m = await linker(specifier, this); + if (!m || !wrapMap.has(m)) + throw new errors.Error('ERR_VM_MODULE_NOT_MODULE'); + if (m.context !== this.context) + throw new errors.Error('ERR_VM_MODULE_DIFFERENT_CONTEXT'); + const childLinkingStatus = linkingStatusMap.get(m); + if (childLinkingStatus === 'errored') + throw new errors.Error('ERR_VM_MODULE_LINKING_ERRORED'); + if (childLinkingStatus === 'unlinked') + await m.link(linker); + return wrapMap.get(m); }); + try { - await Promise.all(promises); + if (promises !== undefined) + await SafePromise.all(promises); linkingStatusMap.set(this, 'linked'); } catch (err) { linkingStatusMap.set(this, 'errored'); diff --git a/node.gyp b/node.gyp index 160303f69fc..9c398284939 100644 --- a/node.gyp +++ b/node.gyp @@ -107,6 +107,7 @@ 'lib/internal/loader/DefaultResolve.js', 'lib/internal/loader/ModuleJob.js', 'lib/internal/loader/ModuleMap.js', + 'lib/internal/loader/ModuleWrap.js', 'lib/internal/loader/Translators.js', 'lib/internal/safe_globals.js', 'lib/internal/net.js', diff --git a/src/module_wrap.cc b/src/module_wrap.cc index 0fda1250d70..4a9c847a6a0 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -209,7 +209,7 @@ void ModuleWrap::Link(const FunctionCallbackInfo& args) { Local resolve_promise = resolve_return_value.As(); obj->resolve_cache_[specifier_std].Reset(env->isolate(), resolve_promise); - promises->Set(mod_context, specifier, resolve_promise).FromJust(); + promises->Set(mod_context, i, resolve_promise).FromJust(); } args.GetReturnValue().Set(promises); diff --git a/test/parallel/test-internal-module-wrap.js b/test/parallel/test-internal-module-wrap.js new file mode 100644 index 00000000000..634d1ebc6f6 --- /dev/null +++ b/test/parallel/test-internal-module-wrap.js @@ -0,0 +1,29 @@ +'use strict'; + +// Flags: --expose-internals + +const common = require('../common'); +common.crashOnUnhandledRejection(); +const assert = require('assert'); + +const ModuleWrap = require('internal/loader/ModuleWrap'); +const { getPromiseDetails, isPromise } = process.binding('util'); +const setTimeoutAsync = require('util').promisify(setTimeout); + +const foo = new ModuleWrap('export * from "bar"; 6;', 'foo'); +const bar = new ModuleWrap('export const five = 5', 'bar'); + +(async () => { + const promises = foo.link(() => setTimeoutAsync(1000).then(() => bar)); + assert.strictEqual(promises.length, 1); + assert(isPromise(promises[0])); + + await Promise.all(promises); + + assert.strictEqual(getPromiseDetails(promises[0])[1], bar); + + foo.instantiate(); + + assert.strictEqual(await foo.evaluate(), 6); + assert.strictEqual(foo.namespace().five, 5); +})(); From 9974d6a84df96d3a86c576c2a4ec8be9da86e86b Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Sun, 4 Feb 2018 23:58:21 +0200 Subject: [PATCH 3/9] tools: add .mjs linting for Windows PR-URL: https://github.com/nodejs/node/pull/18569 Reviewed-By: Anna Henningsen Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Anatoli Papirovski --- vcbuild.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcbuild.bat b/vcbuild.bat index 91a2bc098a5..5e9f250e43c 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -509,7 +509,7 @@ if defined lint_js_ci goto lint-js-ci if not defined lint_js goto exit if not exist tools\node_modules\eslint goto no-lint echo running lint-js -%config%\node tools\node_modules\eslint\bin\eslint.js --cache --rule "linebreak-style: 0" --rulesdir=tools\eslint-rules --ext=.js,.md benchmark doc lib test tools +%config%\node tools\node_modules\eslint\bin\eslint.js --cache --rule "linebreak-style: 0" --rulesdir=tools\eslint-rules --ext=.js,.mjs,.md benchmark doc lib test tools goto exit :lint-js-ci From b9a873e044045a68104d2c046a272cc87b954301 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 2 Feb 2018 16:25:37 +0100 Subject: [PATCH 4/9] test: fix cctest -Wunused-variable warning PR-URL: https://github.com/nodejs/node/pull/18530 Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Joyee Cheung Reviewed-By: Daniel Bevenius --- test/cctest/test_node_postmortem_metadata.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cctest/test_node_postmortem_metadata.cc b/test/cctest/test_node_postmortem_metadata.cc index 9ba6e15593a..72e6abb585f 100644 --- a/test/cctest/test_node_postmortem_metadata.cc +++ b/test/cctest/test_node_postmortem_metadata.cc @@ -130,7 +130,7 @@ TEST_F(DebugSymbolsTest, ReqWrapList) { // NOTE (mmarchini): Workaround to fix failing tests on ARM64 machines with // older GCC. Should be removed once we upgrade the GCC version used on our // ARM64 CI machinies. - for (auto it : *(*env)->req_wrap_queue()) {} + for (auto it : *(*env)->req_wrap_queue()) (void) ⁢ auto queue = reinterpret_cast((*env)->req_wrap_queue()); auto head = queue + From 83c93158fb0e979dbffb4a776d237da0db8f7b08 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Fri, 2 Feb 2018 10:35:43 +0100 Subject: [PATCH 5/9] test: remove destructor from node_test_fixture This commit removes the destructor from node_test_fixture.h which calls the TearDown function causing TearDown to be called twice. This also allows us to remove the check of the platform_ in TearDown. Also the Setup/TearDown functions in AliasBufferTest are removed as they are not necessary. PR-URL: https://github.com/nodejs/node/pull/18524 Reviewed-By: James M Snell --- test/cctest/node_test_fixture.h | 5 ----- test/cctest/test_aliased_buffer.cc | 11 +---------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/test/cctest/node_test_fixture.h b/test/cctest/node_test_fixture.h index ffecd34d71b..48642d59493 100644 --- a/test/cctest/node_test_fixture.h +++ b/test/cctest/node_test_fixture.h @@ -64,10 +64,6 @@ class NodeTestFixture : public ::testing::Test { protected: v8::Isolate* isolate_; - ~NodeTestFixture() { - TearDown(); - } - virtual void SetUp() { CHECK_EQ(0, uv_loop_init(¤t_loop)); platform_ = new node::NodePlatform(8, nullptr); @@ -86,7 +82,6 @@ class NodeTestFixture : public ::testing::Test { } virtual void TearDown() { - if (platform_ == nullptr) return; platform_->Shutdown(); while (uv_loop_alive(¤t_loop)) { uv_run(¤t_loop, UV_RUN_ONCE); diff --git a/test/cctest/test_aliased_buffer.cc b/test/cctest/test_aliased_buffer.cc index 8dfb02c181c..0eaddf77355 100644 --- a/test/cctest/test_aliased_buffer.cc +++ b/test/cctest/test_aliased_buffer.cc @@ -5,16 +5,7 @@ using node::AliasedBuffer; -class AliasBufferTest : public NodeTestFixture { - protected: - void SetUp() override { - NodeTestFixture::SetUp(); - } - - void TearDown() override { - NodeTestFixture::TearDown(); - } -}; +class AliasBufferTest : public NodeTestFixture {}; template void CreateOracleValues(NativeT* buf, size_t count) { From a52b7a2794a47b9c19968d729856fdaa1597c0eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=88=9A?= Date: Sat, 20 Jan 2018 11:06:26 +0800 Subject: [PATCH 6/9] stream: cleanup() when unpiping all streams. This PR makes sure the object emitted as the 'unpipe' event in the destination stream is not shared between destination, as it would be muted. Refs: https://github.com/nodejs/node/pull/12746 PR-URL: https://github.com/nodejs/node/pull/18266 Reviewed-By: Luigi Pinca Reviewed-By: Anatoli Papirovski Reviewed-By: Matteo Collina Reviewed-By: James M Snell Reviewed-By: Ruben Bridgewater Reviewed-By: Anna Henningsen --- lib/_stream_readable.js | 2 +- .../test-stream-pipe-unpipe-streams.js | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index 19e9e7a7439..dc2c587aed6 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -751,7 +751,7 @@ Readable.prototype.unpipe = function(dest) { state.flowing = false; for (var i = 0; i < len; i++) - dests[i].emit('unpipe', this, unpipeInfo); + dests[i].emit('unpipe', this, { hasUnpiped: false }); return this; } diff --git a/test/parallel/test-stream-pipe-unpipe-streams.js b/test/parallel/test-stream-pipe-unpipe-streams.js index cd29b66365a..49e02bea9cb 100644 --- a/test/parallel/test-stream-pipe-unpipe-streams.js +++ b/test/parallel/test-stream-pipe-unpipe-streams.js @@ -31,3 +31,57 @@ source.unpipe(dest2); source.unpipe(dest1); assert.strictEqual(source._readableState.pipes, null); + +{ + // test `cleanup()` if we unpipe all streams. + const source = Readable({ read: () => {} }); + const dest1 = Writable({ write: () => {} }); + const dest2 = Writable({ write: () => {} }); + + let destCount = 0; + const srcCheckEventNames = ['end', 'data']; + const destCheckEventNames = ['close', 'finish', 'drain', 'error', 'unpipe']; + + const checkSrcCleanup = common.mustCall(() => { + assert.strictEqual(source._readableState.pipes, null); + assert.strictEqual(source._readableState.pipesCount, 0); + assert.strictEqual(source._readableState.flowing, false); + + srcCheckEventNames.forEach((eventName) => { + assert.strictEqual( + source.listenerCount(eventName), 0, + `source's '${eventName}' event listeners not removed` + ); + }); + }); + + function checkDestCleanup(dest) { + const currentDestId = ++destCount; + source.pipe(dest); + + const unpipeChecker = common.mustCall(() => { + assert.deepStrictEqual( + dest.listeners('unpipe'), [unpipeChecker], + `destination{${currentDestId}} should have a 'unpipe' event ` + + 'listener which is `unpipeChecker`' + ); + dest.removeListener('unpipe', unpipeChecker); + destCheckEventNames.forEach((eventName) => { + assert.strictEqual( + dest.listenerCount(eventName), 0, + `destination{${currentDestId}}'s '${eventName}' event ` + + 'listeners not removed' + ); + }); + + if (--destCount === 0) + checkSrcCleanup(); + }); + + dest.on('unpipe', unpipeChecker); + } + + checkDestCleanup(dest1); + checkDestCleanup(dest2); + source.unpipe(); +} From 1f7648272eded182a4276a14083ac618902866e8 Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Fri, 2 Feb 2018 00:44:09 -0800 Subject: [PATCH 7/9] deps: patch V8 to 6.4.388.41 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/18522 Refs: https://github.com/v8/v8/compare/6.4.388.40...6.4.388.41 Reviewed-By: MichaĆ«l Zasso Reviewed-By: Franziska Hinkelmann Reviewed-By: Colin Ihrig --- deps/v8/include/v8-version.h | 2 +- deps/v8/src/factory.cc | 1 + .../mjsunit/regress/regress-crbug-800032.js | 22 +++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-800032.js diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 3503f3fbb4b..dafa83627b2 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 6 #define V8_MINOR_VERSION 4 #define V8_BUILD_NUMBER 388 -#define V8_PATCH_LEVEL 40 +#define V8_PATCH_LEVEL 41 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/factory.cc b/deps/v8/src/factory.cc index fbb8d55bef1..ea3936e2321 100644 --- a/deps/v8/src/factory.cc +++ b/deps/v8/src/factory.cc @@ -1613,6 +1613,7 @@ Handle Factory::NewFunction(const NewFunctionArgs& args) { } Handle initial_map = NewMap(args.type_, args.instance_size_, elements_kind, args.inobject_properties_); + result->shared()->set_expected_nof_properties(args.inobject_properties_); // TODO(littledan): Why do we have this is_generator test when // NewFunctionPrototype already handles finding an appropriately // shared prototype? diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-800032.js b/deps/v8/test/mjsunit/regress/regress-crbug-800032.js new file mode 100644 index 00000000000..7c9206c7f6e --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-800032.js @@ -0,0 +1,22 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --expose-gc + + +class Derived extends RegExp { + constructor(a) { + // Syntax Error + const a = 1; + } +} + +let o = Reflect.construct(RegExp, [], Derived); +%HeapObjectVerify(o); +// Check that we can properly access lastIndex. +assertEquals(o.lastIndex, 0); +o.lastIndex = 1; +assertEquals(o.lastIndex, 1); +o.lastIndex = 0; +gc(); From 47f664ee88eab74f2173acdad7abfd285235de54 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 2 Feb 2018 17:27:01 +0100 Subject: [PATCH 8/9] n-api: wrap control flow macro in do/while Make CHECK_ENV() safe to use in the following context: if (condition) CHECK_ENV(env); else something_else(); PR-URL: https://github.com/nodejs/node/pull/18532 Reviewed-By: Michael Dawson Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Ali Ijaz Sheikh Reviewed-By: Ruben Bridgewater Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Daniel Bevenius --- src/node_api.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/node_api.cc b/src/node_api.cc index 78841d14882..611f6c8085e 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -70,10 +70,12 @@ struct napi_env__ { } \ } while (0) -#define CHECK_ENV(env) \ - if ((env) == nullptr) { \ - return napi_invalid_arg; \ - } +#define CHECK_ENV(env) \ + do { \ + if ((env) == nullptr) { \ + return napi_invalid_arg; \ + } \ + } while (0) #define CHECK_ARG(env, arg) \ RETURN_STATUS_IF_FALSE((env), ((arg) != nullptr), napi_invalid_arg) From d4b605b9903f261c2cadbec3d04822b0de4e14e2 Mon Sep 17 00:00:00 2001 From: Ali Ijaz Sheikh Date: Fri, 2 Feb 2018 15:48:09 -0800 Subject: [PATCH 9/9] doc: expand on promises and async_hooks AsyncHooks have a few subtleties with being able to track promises. This commit adds a section to the docs that explains things the issues. PR-URL: https://github.com/nodejs/node/pull/18540 Fixes: https://github.com/nodejs/node/issues/18520 Reviewed-By: James M Snell --- doc/api/async_hooks.md | 56 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index 781509900cc..e0922fcd113 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -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 @@ -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 @@ -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