Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
squash! properly enter microtask queue
  • Loading branch information
devsnek committed Sep 7, 2018
commit 1626f5998c4647e22a72b6807fafa4b537d9d3a3
20 changes: 19 additions & 1 deletion lib/internal/process/next_tick.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ function setupNextTick(_setupNextTick, _setupPromises) {
// runMicrotasks is used to run V8's micro task queue.
const [
tickInfo,
runMicrotasks
runMicrotasks,
enqueueMicrotask,
] = _setupNextTick(_tickCallback);

// *Must* match Environment::TickInfo::Fields in src/env.h.
Expand Down Expand Up @@ -91,6 +92,23 @@ function setupNextTick(_setupNextTick, _setupPromises) {
}
}

// Internal method to enter the true microtask queue, ensuring that
// the callback isn't called out of order with promise jobs.
function queueMicrotask(callback) {
if (typeof callback !== 'function')
throw new ERR_INVALID_CALLBACK();

enqueueMicrotask(() => {
try {
callback();
} catch (e) {
process.emit('error', e);
}
});
}

exports.queueMicrotask = queueMicrotask;

// `nextTick()` will not enqueue any callback when the process is about to
// exit since the callback would not have a chance to be executed.
function nextTick(callback) {
Expand Down
5 changes: 3 additions & 2 deletions lib/internal/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const locks = internalBinding('locks');
const { clearAsyncIdStack } = require('internal/async_hooks');
const { serializeError, deserializeError } = require('internal/error-serdes');
const DOMException = require('internal/domexception');
const nextTickUtil = require('internal/process/next_tick');

util.inherits(MessagePort, EventEmitter);

Expand Down Expand Up @@ -588,7 +589,7 @@ class LockManager {
// promise, the current agent, environment's id, origin, callback, name,
// options' mode dictionary member, options' ifAvailable dictionary
// member, and option's steal dictionary member.
process.nextTick(() => {
nextTickUtil.queueMicrotask(() => {
locks.request(
promise,
(name, mode, waitingPromise, release) => {
Expand Down Expand Up @@ -635,7 +636,7 @@ class LockManager {
// https://wicg.github.io/web-locks/#api-lock-manager-query
query() {
return new Promise((resolve) => {
process.nextTick(() => {
nextTickUtil.queueMicrotask(() => {
const snapshot = locks.snapshot();
resolve(snapshot);
});
Expand Down
12 changes: 12 additions & 0 deletions src/bootstrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ void RunMicrotasks(const FunctionCallbackInfo<Value>& args) {
args.GetIsolate()->RunMicrotasks();
}

void EnqueueMicrotask(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsFunction());
args.GetIsolate()->EnqueueMicrotask(args[0].As<Function>());
}

void SetupTraceCategoryState(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(args[0]->IsFunction());
Expand All @@ -51,9 +56,16 @@ void SetupNextTick(const FunctionCallbackInfo<Value>& args) {
.ToLocalChecked();
run_microtasks_fn->SetName(FIXED_ONE_BYTE_STRING(isolate, "runMicrotasks"));

Local<Function> enqueue_microtasks_fn =
env->NewFunctionTemplate(EnqueueMicrotask)->GetFunction(context)
.ToLocalChecked();
enqueue_microtasks_fn->SetName(
FIXED_ONE_BYTE_STRING(isolate, "EnqueueMicrotask"));

Local<Array> ret = Array::New(isolate, 2);
ret->Set(context, 0, env->tick_info()->fields().GetJSArray()).FromJust();
ret->Set(context, 1, run_microtasks_fn).FromJust();
ret->Set(context, 2, enqueue_microtasks_fn).FromJust();

args.GetReturnValue().Set(ret);
}
Expand Down