-
Notifications
You must be signed in to change notification settings - Fork 408
Patch process.nextTick() #505
Comments
Yeah, I agree with you, zone.js should patch process.nextTick, process.nextTick is a microtask , if we patch it like the callback will be inzone. such as the following case. ` process.nextTick(function(){console.log('process nexttick')}); should printout process nexttick but with zone.js patched, the result is reversed. |
I don't think wrapping will effect the order at all? |
yes, the zone.wrap will not change the order, what I want to say is patch it just like the code I posted can only resolve the issue that process.nextTick callback not inzone, but it will still be executed after promise.resolve(). such behaviors are different with the native implementations. |
After reading more about micro tasks, I agree. |
I think we need another task queue, sadly |
I believe in nodejs native implementation process.nextTick and promise.resolve use the same microtask queue, so maybe we can patch process.nextTick using the ZoneAwarenessPromise microTaskQueue... |
Nope: var p = (s) => { Promise.resolve().then(() => { console.log(s); }); }
var n = (s) => { process.nextTick(() => { console.log(s); }); }
n(1);
p(3);
n(2);
p(4); Outputs:
On node v6.9.1 |
So I guess your warping is fine? |
in native node without zone.js the result is the same as yours, but with zone.js
|
I switched to Regardless, it's more complicated: nodejs/node-v0.x-archive#8325 Basically, it empties one queue, then switches to the other. It keeps switching back and forth until both queues are empty. For instance, on my machine the following: var p = (c) => { return Promise.resolve().then(c); }
var n = (c) => { process.nextTick(c); }
var q = (s) => {return p(() => {console.log(s + ' (promise)');});}
var m = (s) => {return n(() => {console.log(s + ' (next tick)');});}
m(1);
q(3);
n(() => {
m(2);
q(4);
});
p(() => {
m(6);
q(5);
}); Outputs:
For some reason on my machine it starts with the
Regardless, we definitely need a second queue |
yeah, I saw this issue too, nodejs/node-v0.x-archive#8325, from this PR, in my understanding they use node v8 microtask to proceed the process.nextTick. I will test your code, and see what is the order. |
Yes, I my machine with zone.js the result is |
Oh sorry, I was reading quickly and didn't see that you only got the weird order with zone.js |
I actually loaded up zone.js (at 3b94918) on my ubuntu machine and I still get the |
yes, it seems the patch change the order... I'll check it to find why.. |
I write code like following , the order is still correct. require('./zone-node.js');
var nativeNextTick = process.nextTick;
process.nextTick = function() {
var args = arguments;
args[0] = Zone.current.wrap(args[0], 'process.nextTick');
nativeNextTick.apply(this, args);
}
var p = (c) => { return Promise.resolve().then(c); }
var n = (c) => { process.nextTick(c); }
var q = (s) => {return p(() => {
console.log(s + Zone.current.name + ' (promise)');
});}
var m = (s) => {return n(() => {console.log(s + Zone.current.name + ' (next tick)');});}
Zone.current.fork({name: 'A'}).run(function() {
m(1);
q(3);
n(() => {
m(2);
q(4);
}); |
Oh yeah, I wasn't running inside jasmine. That could be it. |
I did some experimentation:
|
Found the problem: https://github.com/angular/zone.js/blob/master/lib/jasmine/jasmine.ts#L132 As you can see, the jasmine patch runs the tests within a microtask, which therefore makes the microtask queue the active queue, which is why microtasks are being run before |
Yeah! That is the problem, so the order should be correct in real code. |
Yeah, I say we go with your original suggestion for how to patch |
Yeah, I have make a PR #516, and add several cases. |
I change the PR to use zone.scheduleMicroTask to patch the process.nextTick, function patchNextTick() {
let setNative = null;
function scheduleTask(task: Task) {
const args = task.data;
args[0] = function() {
task.invoke.apply(this, arguments);
};
setNative.apply(process, args);
return task;
}
setNative =
patchMethod(process, 'nextTick', (delegate: Function) => function(self: any, args: any[]) {
if (typeof args[0] === 'function') {
const zone = Zone.current;
const task = zone.scheduleMicroTask('nextTick', args[0], args, scheduleTask);
return task;
} else {
// cause an error by calling it directly.
return delegate.apply(process, args);
}
});
} so we can use zoneSpec.onScheduleTask/onInvokeTask to trace the Task lifecycle. |
node's
process.nextTick()
is used by a lot of libraries (q
, for instance) but isn't patched by zone.js:process.nextTick
was basicallysetImmediate
beforesetImmediate
existed. Now it's likesetImmediate
except it gets scheduled in a higher priority queue.The text was updated successfully, but these errors were encountered: