Skip to content

Commit 2e33ad1

Browse files
joyeecheungBridgeAR
authored andcommittedJan 17, 2019
src: move process.nextTick and promise setup into node_task_queue.cc
This patch: - Moves the process.nextTick and promise setup C++ code into node_task_queue.cc which is exposed as `internalBinding('task_queue')` - Makes `lib/internal/process/promises.js` and `lib/internal/process/next_tick.js` as side-effect-free as possible - Removes the bootstrapper object being passed into `bootstrap/node.js`, let `next_tick.js` and `promises.js` load whatever they need from `internalBinding('task_queue')` instead. - Rename `process._tickCallback` to `runNextTicks` internally for clarity but still expose it as `process._tickCallback`. PR-URL: #25163 Refs: #24961 Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Anatoli Papirovski <[email protected]>
1 parent fa74cd3 commit 2e33ad1

13 files changed

+199
-192
lines changed
 

‎lib/internal/bootstrap/node.js

+13-7
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,9 @@
1414

1515
// This file is compiled as if it's wrapped in a function with arguments
1616
// passed by node::LoadEnvironment()
17-
/* global process, bootstrappers, loaderExports, triggerFatalException */
17+
/* global process, loaderExports, triggerFatalException */
1818
/* global isMainThread */
1919

20-
const {
21-
_setupNextTick,
22-
_setupPromises
23-
} = bootstrappers;
2420
const { internalBinding, NativeModule } = loaderExports;
2521

2622
const exceptionHandlerState = { captureFn: null };
@@ -105,8 +101,18 @@ function startup() {
105101
}
106102

107103
NativeModule.require('internal/process/warning').setup();
108-
NativeModule.require('internal/process/next_tick').setup(_setupNextTick,
109-
_setupPromises);
104+
const {
105+
nextTick,
106+
runNextTicks
107+
} = NativeModule.require('internal/process/next_tick').setup();
108+
109+
process.nextTick = nextTick;
110+
// Used to emulate a tick manually in the JS land.
111+
// A better name for this function would be `runNextTicks` but
112+
// it has been exposed to the process object so we keep this legacy name
113+
// TODO(joyeecheung): either remove it or make it public
114+
process._tickCallback = runNextTicks;
115+
110116
const credentials = internalBinding('credentials');
111117
if (credentials.implementsPosixCredentials) {
112118
process.getuid = credentials.getuid;

‎lib/internal/process/next_tick.js

+129-119
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,138 @@
11
'use strict';
22

3-
exports.setup = setupNextTick;
4-
5-
function setupNextTick(_setupNextTick, _setupPromises) {
6-
const {
7-
getDefaultTriggerAsyncId,
8-
newAsyncId,
9-
initHooksExist,
10-
destroyHooksExist,
11-
emitInit,
12-
emitBefore,
13-
emitAfter,
14-
emitDestroy,
15-
symbols: { async_id_symbol, trigger_async_id_symbol }
16-
} = require('internal/async_hooks');
17-
const emitPromiseRejectionWarnings =
18-
require('internal/process/promises').setup(_setupPromises);
19-
const { ERR_INVALID_CALLBACK } = require('internal/errors').codes;
20-
const FixedQueue = require('internal/fixed_queue');
21-
22-
// tickInfo is used so that the C++ code in src/node.cc can
23-
// have easy access to our nextTick state, and avoid unnecessary
24-
// calls into JS land.
25-
// runMicrotasks is used to run V8's micro task queue.
26-
const [
27-
tickInfo,
28-
runMicrotasks
29-
] = _setupNextTick(internalTickCallback);
30-
31-
// *Must* match Environment::TickInfo::Fields in src/env.h.
32-
const kHasScheduled = 0;
33-
const kHasPromiseRejections = 1;
34-
35-
const queue = new FixedQueue();
36-
37-
process.nextTick = nextTick;
38-
// Needs to be accessible from beyond this scope.
39-
process._tickCallback = _tickCallback;
40-
41-
function _tickCallback() {
42-
if (tickInfo[kHasScheduled] === 0 && tickInfo[kHasPromiseRejections] === 0)
43-
runMicrotasks();
44-
if (tickInfo[kHasScheduled] === 0 && tickInfo[kHasPromiseRejections] === 0)
45-
return;
46-
47-
internalTickCallback();
48-
}
49-
50-
function internalTickCallback() {
51-
let tock;
52-
do {
53-
while (tock = queue.shift()) {
54-
const asyncId = tock[async_id_symbol];
55-
emitBefore(asyncId, tock[trigger_async_id_symbol]);
56-
// emitDestroy() places the async_id_symbol into an asynchronous queue
57-
// that calls the destroy callback in the future. It's called before
58-
// calling tock.callback so destroy will be called even if the callback
59-
// throws an exception that is handled by 'uncaughtException' or a
60-
// domain.
61-
// TODO(trevnorris): This is a bit of a hack. It relies on the fact
62-
// that nextTick() doesn't allow the event loop to proceed, but if
63-
// any async hooks are enabled during the callback's execution then
64-
// this tock's after hook will be called, but not its destroy hook.
65-
if (destroyHooksExist())
66-
emitDestroy(asyncId);
67-
68-
const callback = tock.callback;
69-
if (tock.args === undefined)
70-
callback();
71-
else
72-
Reflect.apply(callback, undefined, tock.args);
73-
74-
emitAfter(asyncId);
75-
}
76-
tickInfo[kHasScheduled] = 0;
77-
runMicrotasks();
78-
} while (!queue.isEmpty() || emitPromiseRejectionWarnings());
79-
tickInfo[kHasPromiseRejections] = 0;
80-
}
3+
const {
4+
// For easy access to the nextTick state in the C++ land,
5+
// and to avoid unnecessary calls into JS land.
6+
tickInfo,
7+
// Used to run V8's micro task queue.
8+
runMicrotasks,
9+
setTickCallback,
10+
initializePromiseRejectCallback
11+
} = internalBinding('task_queue');
12+
13+
const {
14+
promiseRejectHandler,
15+
emitPromiseRejectionWarnings
16+
} = require('internal/process/promises');
17+
18+
const {
19+
getDefaultTriggerAsyncId,
20+
newAsyncId,
21+
initHooksExist,
22+
destroyHooksExist,
23+
emitInit,
24+
emitBefore,
25+
emitAfter,
26+
emitDestroy,
27+
symbols: { async_id_symbol, trigger_async_id_symbol }
28+
} = require('internal/async_hooks');
29+
const { ERR_INVALID_CALLBACK } = require('internal/errors').codes;
30+
const FixedQueue = require('internal/fixed_queue');
31+
32+
// *Must* match Environment::TickInfo::Fields in src/env.h.
33+
const kHasScheduled = 0;
34+
const kHasPromiseRejections = 1;
35+
36+
const queue = new FixedQueue();
37+
38+
function runNextTicks() {
39+
if (tickInfo[kHasScheduled] === 0 && tickInfo[kHasPromiseRejections] === 0)
40+
runMicrotasks();
41+
if (tickInfo[kHasScheduled] === 0 && tickInfo[kHasPromiseRejections] === 0)
42+
return;
43+
44+
internalTickCallback();
45+
}
8146

82-
class TickObject {
83-
constructor(callback, args, triggerAsyncId) {
84-
// This must be set to null first to avoid function tracking
85-
// on the hidden class, revisit in V8 versions after 6.2
86-
this.callback = null;
87-
this.callback = callback;
88-
this.args = args;
89-
90-
const asyncId = newAsyncId();
91-
this[async_id_symbol] = asyncId;
92-
this[trigger_async_id_symbol] = triggerAsyncId;
93-
94-
if (initHooksExist()) {
95-
emitInit(asyncId,
96-
'TickObject',
97-
triggerAsyncId,
98-
this);
99-
}
47+
function internalTickCallback() {
48+
let tock;
49+
do {
50+
while (tock = queue.shift()) {
51+
const asyncId = tock[async_id_symbol];
52+
emitBefore(asyncId, tock[trigger_async_id_symbol]);
53+
// emitDestroy() places the async_id_symbol into an asynchronous queue
54+
// that calls the destroy callback in the future. It's called before
55+
// calling tock.callback so destroy will be called even if the callback
56+
// throws an exception that is handled by 'uncaughtException' or a
57+
// domain.
58+
// TODO(trevnorris): This is a bit of a hack. It relies on the fact
59+
// that nextTick() doesn't allow the event loop to proceed, but if
60+
// any async hooks are enabled during the callback's execution then
61+
// this tock's after hook will be called, but not its destroy hook.
62+
if (destroyHooksExist())
63+
emitDestroy(asyncId);
64+
65+
const callback = tock.callback;
66+
if (tock.args === undefined)
67+
callback();
68+
else
69+
Reflect.apply(callback, undefined, tock.args);
70+
71+
emitAfter(asyncId);
10072
}
101-
}
73+
tickInfo[kHasScheduled] = 0;
74+
runMicrotasks();
75+
} while (!queue.isEmpty() || emitPromiseRejectionWarnings());
76+
tickInfo[kHasPromiseRejections] = 0;
77+
}
10278

103-
// `nextTick()` will not enqueue any callback when the process is about to
104-
// exit since the callback would not have a chance to be executed.
105-
function nextTick(callback) {
106-
if (typeof callback !== 'function')
107-
throw new ERR_INVALID_CALLBACK();
108-
109-
if (process._exiting)
110-
return;
111-
112-
var args;
113-
switch (arguments.length) {
114-
case 1: break;
115-
case 2: args = [arguments[1]]; break;
116-
case 3: args = [arguments[1], arguments[2]]; break;
117-
case 4: args = [arguments[1], arguments[2], arguments[3]]; break;
118-
default:
119-
args = new Array(arguments.length - 1);
120-
for (var i = 1; i < arguments.length; i++)
121-
args[i - 1] = arguments[i];
79+
class TickObject {
80+
constructor(callback, args, triggerAsyncId) {
81+
// This must be set to null first to avoid function tracking
82+
// on the hidden class, revisit in V8 versions after 6.2
83+
this.callback = null;
84+
this.callback = callback;
85+
this.args = args;
86+
87+
const asyncId = newAsyncId();
88+
this[async_id_symbol] = asyncId;
89+
this[trigger_async_id_symbol] = triggerAsyncId;
90+
91+
if (initHooksExist()) {
92+
emitInit(asyncId,
93+
'TickObject',
94+
triggerAsyncId,
95+
this);
12296
}
97+
}
98+
}
12399

124-
if (queue.isEmpty())
125-
tickInfo[kHasScheduled] = 1;
126-
queue.push(new TickObject(callback, args, getDefaultTriggerAsyncId()));
100+
// `nextTick()` will not enqueue any callback when the process is about to
101+
// exit since the callback would not have a chance to be executed.
102+
function nextTick(callback) {
103+
if (typeof callback !== 'function')
104+
throw new ERR_INVALID_CALLBACK();
105+
106+
if (process._exiting)
107+
return;
108+
109+
var args;
110+
switch (arguments.length) {
111+
case 1: break;
112+
case 2: args = [arguments[1]]; break;
113+
case 3: args = [arguments[1], arguments[2]]; break;
114+
case 4: args = [arguments[1], arguments[2], arguments[3]]; break;
115+
default:
116+
args = new Array(arguments.length - 1);
117+
for (var i = 1; i < arguments.length; i++)
118+
args[i - 1] = arguments[i];
127119
}
120+
121+
if (queue.isEmpty())
122+
tickInfo[kHasScheduled] = 1;
123+
queue.push(new TickObject(callback, args, getDefaultTriggerAsyncId()));
128124
}
125+
126+
// TODO(joyeecheung): make this a factory class so that node.js can
127+
// control the side effects caused by the initializers.
128+
exports.setup = function() {
129+
// Initializes the per-isolate promise rejection callback which
130+
// will call the handler being passed into this function.
131+
initializePromiseRejectCallback(promiseRejectHandler);
132+
// Sets the callback to be run in every tick.
133+
setTickCallback(internalTickCallback);
134+
return {
135+
nextTick,
136+
runNextTicks
137+
};
138+
};

‎lib/internal/process/promises.js

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
'use strict';
22

33
const { safeToString } = internalBinding('util');
4+
const {
5+
promiseRejectEvents
6+
} = internalBinding('task_queue');
47

58
const maybeUnhandledPromises = new WeakMap();
69
const pendingUnhandledRejections = [];
710
const asyncHandledRejections = [];
8-
const promiseRejectEvents = {};
911
let lastPromiseId = 0;
1012

11-
exports.setup = setupPromises;
12-
13-
function setupPromises(_setupPromises) {
14-
_setupPromises(handler, promiseRejectEvents);
15-
return emitPromiseRejectionWarnings;
16-
}
17-
18-
function handler(type, promise, reason) {
13+
function promiseRejectHandler(type, promise, reason) {
1914
switch (type) {
2015
case promiseRejectEvents.kPromiseRejectWithNoHandler:
2116
return unhandledRejection(promise, reason);
@@ -124,3 +119,8 @@ function emitPromiseRejectionWarnings() {
124119
}
125120
return maybeScheduledTicks || pendingUnhandledRejections.length !== 0;
126121
}
122+
123+
module.exports = {
124+
promiseRejectHandler,
125+
emitPromiseRejectionWarnings
126+
};

‎node.gyp

+1-1
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,6 @@
327327

328328
'sources': [
329329
'src/async_wrap.cc',
330-
'src/bootstrapper.cc',
331330
'src/callback_scope.cc',
332331
'src/cares_wrap.cc',
333332
'src/connect_wrap.cc',
@@ -374,6 +373,7 @@
374373
'src/node_serdes.cc',
375374
'src/node_stat_watcher.cc',
376375
'src/node_symbols.cc',
376+
'src/node_task_queue.cc',
377377
'src/node_trace_events.cc',
378378
'src/node_types.cc',
379379
'src/node_url.cc',

‎src/env.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
362362
V(performance_entry_template, v8::Function) \
363363
V(pipe_constructor_template, v8::FunctionTemplate) \
364364
V(process_object, v8::Object) \
365-
V(promise_handler_function, v8::Function) \
365+
V(promise_reject_callback, v8::Function) \
366366
V(promise_wrap_template, v8::ObjectTemplate) \
367367
V(sab_lifetimepartner_constructor_template, v8::FunctionTemplate) \
368368
V(script_context_constructor_template, v8::FunctionTemplate) \
@@ -377,7 +377,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
377377
V(tty_constructor_template, v8::FunctionTemplate) \
378378
V(udp_constructor_function, v8::Function) \
379379
V(url_constructor_function, v8::Function) \
380-
V(write_wrap_template, v8::ObjectTemplate) \
380+
V(write_wrap_template, v8::ObjectTemplate)
381381

382382
class Environment;
383383

‎src/node.cc

-6
Original file line numberDiff line numberDiff line change
@@ -1163,20 +1163,14 @@ void LoadEnvironment(Environment* env) {
11631163
return;
11641164
}
11651165

1166-
// Bootstrap Node.js
1167-
Local<Object> bootstrapper = Object::New(env->isolate());
1168-
SetupBootstrapObject(env, bootstrapper);
1169-
11701166
// process, bootstrappers, loaderExports, triggerFatalException
11711167
std::vector<Local<String>> node_params = {
11721168
env->process_string(),
1173-
FIXED_ONE_BYTE_STRING(isolate, "bootstrappers"),
11741169
FIXED_ONE_BYTE_STRING(isolate, "loaderExports"),
11751170
FIXED_ONE_BYTE_STRING(isolate, "triggerFatalException"),
11761171
FIXED_ONE_BYTE_STRING(isolate, "isMainThread")};
11771172
std::vector<Local<Value>> node_args = {
11781173
process,
1179-
bootstrapper,
11801174
loader_exports.ToLocalChecked(),
11811175
env->NewFunctionTemplate(FatalException)
11821176
->GetFunction(context)

‎src/node_binding.cc

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
V(stream_wrap) \
5353
V(string_decoder) \
5454
V(symbols) \
55+
V(task_queue) \
5556
V(tcp_wrap) \
5657
V(timers) \
5758
V(trace_events) \

‎src/node_internals.h

-2
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,6 @@ v8::Maybe<bool> ProcessEmitDeprecationWarning(Environment* env,
185185
const char* warning,
186186
const char* deprecation_code);
187187

188-
void SetupBootstrapObject(Environment* env,
189-
v8::Local<v8::Object> bootstrapper);
190188
void SetupProcessObject(Environment* env,
191189
const std::vector<std::string>& args,
192190
const std::vector<std::string>& exec_args);

‎src/bootstrapper.cc ‎src/node_task_queue.cc

+40-42
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#include "node.h"
21
#include "env-inl.h"
2+
#include "node.h"
33
#include "node_internals.h"
44
#include "v8.h"
55

@@ -23,36 +23,21 @@ using v8::Object;
2323
using v8::Promise;
2424
using v8::PromiseRejectEvent;
2525
using v8::PromiseRejectMessage;
26-
using v8::String;
2726
using v8::Value;
2827

29-
void RunMicrotasks(const FunctionCallbackInfo<Value>& args) {
28+
namespace task_queue {
29+
30+
static void RunMicrotasks(const FunctionCallbackInfo<Value>& args) {
3031
args.GetIsolate()->RunMicrotasks();
3132
}
3233

33-
void SetupNextTick(const FunctionCallbackInfo<Value>& args) {
34+
static void SetTickCallback(const FunctionCallbackInfo<Value>& args) {
3435
Environment* env = Environment::GetCurrent(args);
35-
Isolate* isolate = env->isolate();
36-
Local<Context> context = env->context();
37-
3836
CHECK(args[0]->IsFunction());
39-
4037
env->set_tick_callback_function(args[0].As<Function>());
41-
42-
Local<Function> run_microtasks_fn =
43-
env->NewFunctionTemplate(RunMicrotasks)->GetFunction(context)
44-
.ToLocalChecked();
45-
run_microtasks_fn->SetName(FIXED_ONE_BYTE_STRING(isolate, "runMicrotasks"));
46-
47-
Local<Value> ret[] = {
48-
env->tick_info()->fields().GetJSArray(),
49-
run_microtasks_fn
50-
};
51-
52-
args.GetReturnValue().Set(Array::New(isolate, ret, arraysize(ret)));
5338
}
5439

55-
void PromiseRejectCallback(PromiseRejectMessage message) {
40+
static void PromiseRejectCallback(PromiseRejectMessage message) {
5641
static std::atomic<uint64_t> unhandledRejections{0};
5742
static std::atomic<uint64_t> rejectionsHandledAfter{0};
5843

@@ -64,7 +49,7 @@ void PromiseRejectCallback(PromiseRejectMessage message) {
6449

6550
if (env == nullptr) return;
6651

67-
Local<Function> callback = env->promise_handler_function();
52+
Local<Function> callback = env->promise_reject_callback();
6853
Local<Value> value;
6954
Local<Value> type = Number::New(env->isolate(), event);
7055

@@ -104,35 +89,48 @@ void PromiseRejectCallback(PromiseRejectMessage message) {
10489
env->tick_info()->promise_rejections_toggle_on();
10590
}
10691

107-
void SetupPromises(const FunctionCallbackInfo<Value>& args) {
92+
static void InitializePromiseRejectCallback(
93+
const FunctionCallbackInfo<Value>& args) {
10894
Environment* env = Environment::GetCurrent(args);
10995
Isolate* isolate = env->isolate();
11096

11197
CHECK(args[0]->IsFunction());
112-
CHECK(args[1]->IsObject());
113-
114-
Local<Object> constants = args[1].As<Object>();
115-
116-
NODE_DEFINE_CONSTANT(constants, kPromiseRejectWithNoHandler);
117-
NODE_DEFINE_CONSTANT(constants, kPromiseHandlerAddedAfterReject);
118-
NODE_DEFINE_CONSTANT(constants, kPromiseResolveAfterResolved);
119-
NODE_DEFINE_CONSTANT(constants, kPromiseRejectAfterResolved);
12098

99+
// TODO(joyeecheung): this may be moved to somewhere earlier in the bootstrap
100+
// to make sure it's only called once
121101
isolate->SetPromiseRejectCallback(PromiseRejectCallback);
122-
env->set_promise_handler_function(args[0].As<Function>());
102+
103+
env->set_promise_reject_callback(args[0].As<Function>());
123104
}
124105

125-
#define BOOTSTRAP_METHOD(name, fn) env->SetMethod(bootstrapper, #name, fn)
106+
static void Initialize(Local<Object> target,
107+
Local<Value> unused,
108+
Local<Context> context,
109+
void* priv) {
110+
Environment* env = Environment::GetCurrent(context);
111+
Isolate* isolate = env->isolate();
126112

127-
// The Bootstrapper object is an ephemeral object that is used only during
128-
// the bootstrap process of the Node.js environment. A reference to the
129-
// bootstrap object must not be kept around after the bootstrap process
130-
// completes so that it can be gc'd as soon as possible.
131-
void SetupBootstrapObject(Environment* env,
132-
Local<Object> bootstrapper) {
133-
BOOTSTRAP_METHOD(_setupNextTick, SetupNextTick);
134-
BOOTSTRAP_METHOD(_setupPromises, SetupPromises);
113+
env->SetMethod(target, "setTickCallback", SetTickCallback);
114+
env->SetMethod(target, "runMicrotasks", RunMicrotasks);
115+
target->Set(env->context(),
116+
FIXED_ONE_BYTE_STRING(isolate, "tickInfo"),
117+
env->tick_info()->fields().GetJSArray()).FromJust();
118+
119+
Local<Object> events = Object::New(isolate);
120+
NODE_DEFINE_CONSTANT(events, kPromiseRejectWithNoHandler);
121+
NODE_DEFINE_CONSTANT(events, kPromiseHandlerAddedAfterReject);
122+
NODE_DEFINE_CONSTANT(events, kPromiseResolveAfterResolved);
123+
NODE_DEFINE_CONSTANT(events, kPromiseRejectAfterResolved);
124+
125+
target->Set(env->context(),
126+
FIXED_ONE_BYTE_STRING(isolate, "promiseRejectEvents"),
127+
events).FromJust();
128+
env->SetMethod(target,
129+
"initializePromiseRejectCallback",
130+
InitializePromiseRejectCallback);
135131
}
136-
#undef BOOTSTRAP_METHOD
137132

133+
} // namespace task_queue
138134
} // namespace node
135+
136+
NODE_MODULE_CONTEXT_AWARE_INTERNAL(task_queue, node::task_queue::Initialize)

‎test/message/events_unhandled_error_nexttick.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Error
1616
Emitted 'error' event at:
1717
at process.nextTick (*events_unhandled_error_nexttick.js:*:*)
1818
at internalTickCallback (internal/process/next_tick.js:*:*)
19-
at process._tickCallback (internal/process/next_tick.js:*:*)
19+
at process.runNextTicks [as _tickCallback] (internal/process/next_tick.js:*:*)
2020
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
2121
at executeUserCode (internal/bootstrap/node.js:*:*)
2222
at startExecution (internal/bootstrap/node.js:*:*)

‎test/message/nexttick_throw.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
ReferenceError: undefined_reference_error_maker is not defined
66
at *test*message*nexttick_throw.js:*:*
77
at internalTickCallback (internal/process/next_tick.js:*:*)
8-
at process._tickCallback (internal/process/next_tick.js:*:*)
8+
at process.runNextTicks [as _tickCallback] (internal/process/next_tick.js:*:*)
99
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
1010
at executeUserCode (internal/bootstrap/node.js:*:*)
1111
at startExecution (internal/bootstrap/node.js:*:*)

‎test/message/unhandled_promise_trace_warnings.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
at *
4343
(node:*) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
4444
at handledRejection (internal/process/promises.js:*)
45-
at handler (internal/process/promises.js:*)
45+
at promiseRejectHandler (internal/process/promises.js:*)
4646
at Promise.then *
4747
at Promise.catch *
4848
at Immediate.setImmediate (*test*message*unhandled_promise_trace_warnings.js:*)

‎test/parallel/test-bootstrap-modules.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const common = require('../common');
99
const assert = require('assert');
1010

1111
const isMainThread = common.isMainThread;
12-
const kMaxModuleCount = isMainThread ? 62 : 82;
12+
const kMaxModuleCount = isMainThread ? 63 : 83;
1313

1414
assert(list.length <= kMaxModuleCount,
1515
`Total length: ${list.length}\n` + list.join('\n')

0 commit comments

Comments
 (0)
Please sign in to comment.