-
Notifications
You must be signed in to change notification settings - Fork 7.3k
doc: WIP update timers/nextTick documentation #5950
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -456,14 +456,19 @@ This will generate: | |
|
||
* `callback` {Function} | ||
|
||
Once the current event loop turn runs to completion, call the callback | ||
function. | ||
Schedule a callback to run immediately after all currently running synchronous | ||
operations. | ||
|
||
This is *not* a simple alias to `setTimeout(fn, 0)`, it's much more | ||
efficient. It runs before any additional I/O events (including | ||
timers) fire in subsequent ticks of the event loop. | ||
This is subject to change in the future. | ||
|
||
The `nextTickQueue` are callbacks that will be called immediately after the | ||
currently running callback, and before continuing with the event loop. Recursive | ||
`nextTick` calls will then have the same effect as a `while(true);` loop. | ||
|
||
console.log('start'); | ||
setImmediate(function() { | ||
console.log('setImmediate callback'); | ||
}); | ||
process.nextTick(function() { | ||
console.log('nextTick callback'); | ||
}); | ||
|
@@ -472,17 +477,20 @@ timers) fire in subsequent ticks of the event loop. | |
// start | ||
// scheduled | ||
// nextTick callback | ||
// setImmediate callback | ||
|
||
This is important in developing APIs where you want to give the user the | ||
chance to assign event handlers after an object has been constructed, | ||
but before any I/O has occurred. | ||
`process.nextTick` is specifically important when developing an event based API | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would like to deemphasize this in favor of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, I used to know why to call Can someone explain why node shouldn't just do And make some clear statement in the docs about under what circumstances Most reasonable use for deferred callbacks is when returning an EE, and In those cases, is the prefered API now .setImmediate, or is it still There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAIK The setImmediate queue is dispatched only once per event loop turn, like so: 1.- Grab the setImmediateQueue, call it currentSetImmediateQueue, But the netTick queue is serviced more than once, as often as needed per event loop turn, like so: while (nextTickQueue.length) nextTickQueue.shift()() So: 1.- When you add an item to the nextTickQueue from a function in the nextTickQueue, it will simply make that (*) Any other cb that was already in the nextTickQueue will still run before There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what @xk says is right, I would like to add the emphasis that when you do queue with The fact that this logic makes it nice to make sure your cb will fire "before" others, is a side effect and shouldn't be relied upon outside of core anyway, hence my insistence to deemphasize the use of (Also There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So is it safe to say we can just use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's safe to say, you want to use |
||
when you need to allow the developer time to setup the event handlers after an | ||
object has been constructed, but perform a task before any other asynchronous | ||
events have fired (e.g. I/O). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not strictly true. Consider: var tick = false;
process.nextTick(function() { tick = true });
process.whatever(); // native function that MakeCallback()'s into JS land again somehow
assert(tick == true); // passes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that shouldn't happen. There's an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i.e. the callback passed to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, so there is. It's still making the call into JS land, isn't it? Future optimization. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch. made the patch: #5952 |
||
|
||
function MyThing(options) { | ||
this.setupOptions(options); | ||
|
||
var ts = this; | ||
process.nextTick(function() { | ||
this.startDoingStuff(); | ||
}.bind(this)); | ||
ts.startDoingStuff(); | ||
}); | ||
} | ||
|
||
var thing = new MyThing(); | ||
|
@@ -494,39 +502,41 @@ It is very important for APIs to be either 100% synchronous or 100% | |
asynchronous. Consider this example: | ||
|
||
// WARNING! DO NOT USE! BAD UNSAFE HAZARD! | ||
function maybeSync(arg, cb) { | ||
function maybeSync(path, arg, cb) { | ||
if (arg) { | ||
cb(); | ||
return; | ||
} | ||
|
||
fs.stat('file', cb); | ||
fs.stat(path, cb); | ||
} | ||
|
||
This API is hazardous. If you do this: | ||
The above now seems ambiguous whether the callback will be called before the | ||
currently running script continues: | ||
|
||
maybeSync(true, function() { | ||
maybeSync('/path', /* maybe truthy */, function() { | ||
foo(); | ||
}); | ||
bar(); | ||
|
||
then it's not clear whether `foo()` or `bar()` will be called first. | ||
If the second `maybeSync()` argument is truthy then `foo()` will run before | ||
`bar()`. Otherwise `bar()` will run before `foo()`. This type of design decision | ||
creates unnecessary confusion, and should be avoided. | ||
|
||
This approach is much better: | ||
|
||
function definitelyAsync(arg, cb) { | ||
function definitelyAsync(path, arg, cb) { | ||
if (arg) { | ||
process.nextTick(cb); | ||
return; | ||
} | ||
|
||
fs.stat('file', cb); | ||
fs.stat(path, cb); | ||
} | ||
|
||
Note: the nextTick queue is completely drained on each pass of the | ||
event loop **before** additional I/O is processed. As a result, | ||
recursively setting nextTick callbacks will block any I/O from | ||
happening, just like a `while(true);` loop. | ||
Note to module developers: Make sure to use the `MakeCallback` API when calling | ||
a JS callback from C++ after an asynchronous operation. This is the only way to | ||
drain the `nextTickQueue`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe be a bit more explicit and/or point to a place where we can also talk about domain handling from MakeCallback? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll add documentation on its use to the module doc and link to it from here. |
||
|
||
## process.umask([mask]) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,16 +5,36 @@ | |
All of the timer functions are globals. You do not need to `require()` | ||
this module in order to use them. | ||
|
||
Timers set to run in the same tick of the event loop will all run in succession: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's strange to see it spelled out here, only to be immediately contradicted in the following graphs, given that we explicitly don't guarantee the firing ordering. This description is true right now, but because that's implementation, however in the future that may not be the case. The developer should only care that node has made the best effort to delay before this function is called, not about the ordering of others. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The use of "succession" was not to imply a specific ordering, but that all callbacks will run immediately after each other (in some undefined order) without continuing though the event loop. Poor wording if you've found it confusing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be easier to talk about the implementation detail of the buckets in that regard then |
||
|
||
function cb(arg) { | ||
return function() { | ||
console.log(arg); | ||
process.nextTick(function() { | ||
console.log('nextTick - ' + arg); | ||
}); | ||
} | ||
} | ||
|
||
setTimeout(cb('0'), 100); | ||
setTimeout(cb('1'), 100); | ||
|
||
// output: | ||
// 0 | ||
// 1 | ||
// nextTick - 0 | ||
// nextTick - 1 | ||
|
||
## setTimeout(callback, delay, [arg], [...]) | ||
|
||
To schedule execution of a one-time `callback` after `delay` milliseconds. Returns a | ||
`timeoutId` for possible use with `clearTimeout()`. Optionally you can | ||
To schedule execution of a one-time `callback` after `delay` milliseconds. | ||
Returns a `timeoutId` for possible use with `clearTimeout()`. Optionally you can | ||
also pass arguments to the callback. | ||
|
||
It is important to note that your callback will probably not be called in exactly | ||
`delay` milliseconds - Node.js makes no guarantees about the exact timing of when | ||
the callback will fire, nor of the ordering things will fire in. The callback will | ||
be called as close as possible to the time specified. | ||
It is important to note that your callback will probably not be called in | ||
exactly `delay` milliseconds - Node.js makes no guarantees about the exact | ||
timing of when the callback will fire, nor of the ordering things will fire in. | ||
The callback will be called as close as possible to the time specified. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe "near" instead of "close" at first glance today I thought this was close as in the closing of a file descriptor :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Heh. Sounds good. |
||
|
||
## clearTimeout(timeoutId) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What changes are planned? This should either be removed, or expressed as a Stability level on this section.
EDIT: That is, this specific line should definitely be removed, and perhaps expressed as a Stability level, if changes are planned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/cc @bnoordhuis
Ben mentioned it would be good to put this in the docs.