Comments (18)
PR #24 is a topic on async programming, which seems a natural place to describe this.
from docs.
I think it makes more sense for it to be reference. The information provided is specific to the behaviour of those functions.
from docs.
I'm in favor of getting better docs for the highly misunderstood timers. process.nextTick
doesn't seems to be replaceable by setImmediate
simply because setImmediate
doesn't have a deterministic behaviour when used with setTimeout
but process.nextTick
seems to do so. See nodejs/node-v0.x-archive#25788
cc @davepacheco
from docs.
In what situations would it make sense to continue using process.nextTick() over setImmediate()?
from docs.
I watched a NodeSource "Need to Node" presentation hosted by @trevnorris called "Event Scheduling and the Node.js Event Loop" that very clearly explained the nuances and gotchas (setImmediate and nextTick should have their names swapped to be conceptually accurate, but they are likely not to change for a long time if ever due to historical precedent).
I'll put together a transcription of that presentation to help clarify the behaviors of the different timers.
from docs.
I believe I understand the behavior (though more clarification is certainly helpful -- I tried to describe it for the official docs under nodejs/node-v0.x-archive#6725), but I'm not aware of any situations where nextTick() is required where the same behavior cannot be more clearly written with setImmediate(). A concrete example would be very helpful.
from docs.
@davepacheco would that then mean that the internal use of process.nextTick
is historic? Because it's used quite often. If it's that easy core should remove those as a best practice, no?
from docs.
Well, I may be wrong about that, and that's why I'm looking for cases where nextTick is considered necessary. But yes, I wonder if many instances of nextTick() could be replaced with setImmediate(). I suspect that would be more complicated than simply replacing the function call because in many cases the code as written today depends on the fact that such events are processed sooner. That doesn't mean nextTick() is actually necessary, just that it requires more significant refactoring than just replacing the function call.
I've also heard performance thrown out as a reason to prefer nextTick(), and that may be why it's used internally. But I'm not sure what data supports that, and I suspect that for most users of Node, the added complexity in their own code is not worth it.
from docs.
@davepacheco At times it's necessary to allow a callback to run before the event loop proceeds. One example is to match user's expectations. Simple example:
var server = net.createServer();
server.on('connection', function(conn) { });
server.listen(8080);
server.on('listening', function() { });
Say that listen()
is run at the beginning of the event loop, but the listening
callback is placed in a setImmediate
. Now, unless a hostname is passed binding to the port will happen immediately. Now for the event loop to proceed it must hit the polling phase, which means there is a non-zero chance that a connection could have been received. Allowing the connection
event to be fired before the listening
event.
from docs.
@trevnorris Thanks for that example. In that case, all of the event management is handled in the "server" class, and it seems like that class could ensure that 'listening' has been emitted before emitting 'connection' (e.g., by checking a flag and queueing any 'connection' events, for example), right? All things being equal, that implementation would seem clearer to me than having two tiers of "immediate" events.
from docs.
@davepacheco That logic would then need to be properly implemented across any class where that type of race condition can occur. Which, in node, is almost all of them. Instead, simply having a timing mechanism of "run after the call stack has unwound but before the event loop continues" is a simple way to queue callbacks that run asynchronously and prevent that race from occurring.
Also we're not recognizing the need for timing consistency. If I schedule a setImmediate
from epoll then it will be the next thing to run. But if I schedule setImmediate
from another setImmediate
, or a timer, then both timers and I/O will be processed. (it is not a typo that timers are processed after timers; this is the case for using UV_RUN_ONCE
which node uses).
To demonstrate how necessary a timing mechanism like nextTick()
is, I'll demonstrate the same using v8's own API:
setImmediate(() => process._rawDebug('setImmediate'));
(function runner() {
Promise.resolve(1).then(runner);
}());
setImmediate
will never be printed. This is because Promises internally use a mechanism that operates fundamentally the same way as the nextTickQueue
. They did this because the additional overhead of needing to wait until the event loop ran around was too great. This is also a case for node's usage.
from docs.
Do you think this problem is unique to core code, where it's possible to perform actions like binding a new file descriptor synchronously as you described in your example? I've managed to never hit this writing my own code outside of core, but I wouldn't be surprised if this issue only happens when using the internal bindings that core uses. I'm also not sure what prevents the timing problem you describe from being recursive. Why is it never necessary to enqueue an event that will happen before the nextTick() handlers? Or before the handlers that happen before the nextTick handlers, and so on?
I'm not making any recommendations for core code because I haven't reviewed much of it. In all the cases I have seen, though, including your example, I felt the code was more clearly written with setImmediate() and explicitly coding the desired behavior, rather than relying on the subtle timing semantics of an interface like nextTick(). I don't think implementing the logic in multiple places is so bad, either. Common logic can be abstracted into common code. And as I said, I don't believe I've run into this, so I'm not sure it would be commonly needed outside core anyway.
But the reason we've gotten here is because many users have expressed a lot of confusion about this interface. I'm seriously doubtful that the existence of nextTick() as a public interface, either to implement those implicit semantics or for performance, is worth all that confusion.
from docs.
Do you think this problem is unique to core code, where it's possible to perform actions like binding a new file descriptor synchronously as you described in your example?
One more important usage is in error handling. In conjunction with the ideal of maintaining that all events are asynchronous, it's important that errors are reported before the event loop is allowed to continue.
Say, for example, your interface is working with a data stream. There is an error in the data stream that must be reported. The error passed to the event indicates that the data stream should be terminated. If that error has been propagated through setImmediate()
then it's possible the data stream could have received additional data. Instead of having been closed "immediately".
Also if I'm writing a native module that creates an interface, which has the same timing constraints as creating a net server, in that it may happen immediately or it may not, for proper propagation of events it's important that the "connection", "listening", etc. event be emitted nextTick()
style. While I could control that timing in my own logic, it's simpler to just use a built-in mechanism that does it for me.
I'm not saying that usage of nextTick()
should be advocated. In fact I'd probably just simply put "if you're not sure whether you should use setImmediate()
or nextTick()
then you should use setImmediate()
". I am saying that there are real use cases for it that a few people may need. So it should remain a public API.
from docs.
@trevnorris That example is another case where ordering of events is important, but nextTick() is not strictly required to implement it. I don't believe it really is simpler to use it.
As for the action items at hand: I've submitted my suggested docs and weighed in a bunch on why, but obviously it's not my decision.
from docs.
@davepacheco So it's easier to implement logic that handles proper event ordering than simply calling process.nextTick(fn)
?
from docs.
Pushed an update to nodejs/node#4936, PTAL
from docs.
In the current documentation, it says if you move the two calls within an I/O cycle, the immediate callback is always executed first
and gives a code snippet:
// timeout_vs_immediate.js
const fs = require('fs');
fs.readFile(__filename, () => {
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
});
I think it's the same if we put the two timers into another setTimeout
callback(immediate
in the check phase of the first event loop and timeout
in the timer phase of the second event loop). But the code below doesn't work as expected:
setTimeout(() => { // timer a
setTimeout(() => { // timer b
console.log('timeout');
}, 0);
setImmediate(() => { // timer c
console.log('immediate');
});
}, 0);
The order in which the two timers inside timer-a are executed is non-deterministic. Did I misunderstand the event loop?
from docs.
Closing as this repository is dormant and likely to be archived soon. If this is still an issue, feel free to open it as an issue on the main node repository.
from docs.
Related Issues (20)
- Node v6.3.1 docs: net.Socket HOT 1
- StackOverflow Documentation for Node.js HOT 5
- Circular reference for OS Constants HOT 3
- http ClientRequest documentation unclear about inheritance when visually scanning HOT 2
- .read() stream not fully explained HOT 9
- Rough Meeting Notes (2016-12-01 @ NINA) HOT 8
- What errors can be thrown?
- Async meetings HOT 6
- How-to use LetsEncrypt Guide HOT 13
- Meeting #1 HOT 33
- Add @vsemozhetbyt? HOT 4
- Meeting #2 HOT 2
- descriptions of "The module Object"'s property are not clear HOT 1
- clarity on asynchronous methods throwing exceptions HOT 2
- http.ClientRequest is missing some methods HOT 3
- Package documentation (how to intl) HOT 1
- Decharter this Working Group? HOT 8
- Better wording for modules_all_together HOT 3
- Suggestion: Return type in function declaration & possible option to view types by clicking HOT 2
- Improve the words usage in socket.setTimeout() definition HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from docs.