Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

process: execute nextTick callback after microtask #8376

Closed
wants to merge 1 commit into from

Conversation

shigeki
Copy link

@shigeki shigeki commented Sep 15, 2014

The current process.nextTick callback in a main module is executed before microtasks such as callbacks of Object.observe and Promise while not in the other I/O or timer callbacks as below.

// test1.js 
// check the callback order of process.nextTick and Object.observe in a main module.
var obj = {};

Object.observe(obj, function(changeRecord) {
  console.log('Object.observe callback:', changeRecord);
});

process.nextTick(function() {
  console.log('process.nextTick');
});
obj.a = 1;
$ ~/tmp/oldnode/node-v0.11.13/node test1.js
nextTick
Object.observe
// test2.js
// check the callback order of process.nextTick and Object.observe in a setTimeout callback
var obj = {};

setTimeout(function() {
  Object.observe(obj, function(changeRecord) {
    console.log('Object.observe');
  });

  process.nextTick(function() {
    console.log('nextTick');
  });
  obj.a = 1;
}, 0);
$ ~/tmp/oldnode/node-v0.11.13/node test2.js
Object.observe
nextTick

These inconsistent behaviors would cause issues in the future use of Object.observe and Promise so this fix makes process.nextTick callback always execute after microtasks.

This fix makes process.nextTick callback always execute after
microtasks such as Object.observe and Promise callbacks.
@vkurchatkin
Copy link

@shigeki

These inconsistent behaviors would cause issues in the future use of Object.observe and Promise
do you have any example of such an issue?

@shigeki
Copy link
Author

shigeki commented Sep 15, 2014

do you have any example of such an issue?

Not really because I have not used so much new ES6 features in Node yet. But the process.nextTick callback was changed largely in Node-v0.10 to be called recursively at the end of JS excursion.
I think it would be confusing that process.nextTick is called before microtasks only in a main module not in the other callbacks like the case as

var http = require('http');
var EE = require('events').EventEmitter;
var obj = {};

function EETest(e) {
  Object.observe(obj, function(changeRecord) {
    e.addListener('tick', function() {
      console.log('tick called', changeRecord);
    });
  });
  process.nextTick(function() {
    e.emit('tick');
  });
}

EETest(new EE());
obj.a = 1;

http.createServer(function(req, res) {
  EETest(new EE());
  ++obj.a;
}).listen(8080);

@trevnorris
Copy link

Going to use #8325 once updated.

@trevnorris trevnorris closed this Sep 17, 2014
@shigeki
Copy link
Author

shigeki commented Sep 18, 2014

@trevnorris Let me confirm that you think the inconsistent behaviors of callback order between nextTick and microtask cause no issues in the future.

@vkurchatkin
Copy link

FWIW #8325 doesn't fix this inconsistency. I still don't think it's problem, because anyone relying on specific order of different types of callbacks is making a mistake. See also #6034, the same thing

@shigeki
Copy link
Author

shigeki commented Sep 18, 2014

process.nextTick is different from timers and I/O callbacks because it needs to defined its execution timing clearly as the node.js docs says that

 It runs before any additional I/O events (including timers) fire in subsequent ticks of the event loop. 

Microtasks is newly introduced so that user would not distinguish and understand wheather they are the same as timer, I/O callback or not.
The event loop diagram as below shows that the current behavior is obviously strange the next tick execution timing only in main module.

Node-v0.11.13 event loop diagram

@trevnorris
Copy link

@shigeki run_pending runs all the .write() callbacks, and run_idle runs clearImmediate(). Also no, I don't believe the difference in running order is an issue. Callbacks should be able to run in nondeterministic order. Meaning, the logic of callback calling order that actually matters should be explicitly controlled by user code.

@shigeki
Copy link
Author

shigeki commented Sep 19, 2014

@trevnorris Yes, I omitted them since pending queues is hard to write down correctly in the diagram and idle handle of clearImmediate is nothing to do with nextTick, just dummy. As for the callback order of nextTick if you think so, let this as is. I just hope it will not cause issues in the future.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants