--
uh, oh.
--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to
nodejs+un...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en
I don't really know how node knows when to run a function asynchronously or not.
--
uh, oh.
--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to
nodejs+un...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en
This is exactly what process.nextTick is for. It defers your callback to a new stack.
If you have some cpu intensive task that takes a long time, then that's bad for node. All javascript executin is blocking. This is normally ok because we're just setting up other background tasks (listening for packets, starting FS operations, starting timers, etc..) and returning right away. If I were to count to a million a million times in two nested for loops, that would be very bad. Using process.nextTick won't help here because it will just defer your expensive task to a later task. But once your callback gets called, the event loop is blocked till you return. Usually it's best to put these kinds of tasks in different processes (probably even using not node, it's not the best for CPU intensive tasks). If you must do a long running CPU task in node, you'll have to manually break it into small enough chunks and execute each one on it's own stack using recursive process.nextTick calls.
var state = "none" ;function foo () {iThinkThisIsAsync(function () {state = "done" ;}) ;state = "started" ;}
> If you call the callback right away, this could break the caller's code if they had assumed it was an async function.But it would be the caller's fault. No one should assume anything about callbacks. I can't think of any use case that can't be coded properly for this.
var net = require('net');
var client = net.connect(8124, function() { //'connect' listener
client.write('world!\r\n');
});
I don't really know how node knows when to run a function asynchronously or not.
--
uh, oh.
Supposing I'm writing a database query (or any I/O related request
really) and I have an in-memory cache. In the first line of my
function (or near it), I will often have code like this:
var cache = {};
function loadResource(key, callback) {
if (cache.hasOwnProperty(key)) {
callback(null, cache[key]);
return;
}
...
}
This is fine and works, except if the caller had assumed that the
function was always async. Simply saying it's caller's fault is
really dumb. What you can do that's responsible is document in your
signature for this function that the callback may be called
synchronously. Then hope that all users of your library actually read
the docs and see this warning. Then it's on them if they don't guard
against this hazard.
The other option is to not have the hazard! For example:
var cache = {};
function loadResource(key, callback) {
if (cache.hasOwnProperty(key)) {
var value = cache[key];
process.nextTick(function () {
callback(null, value);
});
return;
}
...
}
Here the caller can safely assume that their callback won't be called
in the same tick that they set it up. (Though it's still good to
document this fact, especially if the API is mixed in style). This is
a very powerful assumption and makes life much easier for the caller.
The downside is your code is slightly slower. The nextTick mechanism
is pretty fast, but not as fast as a synchronous call. And remember,
performance is all relative. This only matters in certain hot path
cases.
I've written libraries exposing both styles. Sometimes I really need
the performance of a synchronous call and had to adjust my calling
code to take this into account. It made my code significantly harder
to read and often a landmine field of potential bugs. My
recommendation is that whenever you can afford the slight performance
cost, make your API consistent and always call the callback
asynchronously. Especially in the case of a in-memory cache in front
of a expensive resource, this is a no-brainer. It's already several
orders of magnitude faster than actually making the call.
-Tim Caswell
We have process.nextTick if there's no actual async work to do. If
Server.listen becomes synchronous ever, then the cb will be processed
on the next tick.
> If an API is synchronous, it must always be synchronous, no exceptions.
Events are asynchronous, but EventEmitter.emit() emits synchronously.
--
Jorge.
No. *IO* is asynchronous. EventEmitter.emit() is synchronous, always.
If this was not the case, then you wouldn't be able to properly handle
http requests, because you'd randomly miss the first "data" event some
of the time.
By the same token, fs.open(file, cb) is asynchronous (it asks the
system to do some IO, and then call the some time cb in the future),
but cb(er, result) is synchronous (it calls the function NOW.)
EventEmitter.emit() is like calling the function. It might be called
at some time in the future, but *when it's called*, it's called
immediately.
Because you'll run into strange edge cases where code like this works
one way part of the time, and another way when cached:
var bar
var foo = createServer(arg, function (er, result) {
// can you access foo in here?
bar = 10
})
// is bar 10 or undefined here?
So far, every time I've broken this rule, it's been a disaster
eventually. You just have to start to have a pain-aversion reaction
to APIs that are not contractually obligated to be either async or
sync, all the time.
Great explanation with better real-world examples:
http://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/
What are you saying Isaac ?
You would not miss anything if .emit() was not synchronous, it would simply emit a turn (of the event loop) later (that is: asynchronously).
--
Jorge.
I apologize for prolonging this thread, but the discussion is very good.
Tell me if I have these points right.
0. Callbacks are no more "magical" in node than in any language with first-class functions.
1. JavaScript/V8 is single-threaded and never gets prempted.
2. process.nextTick simply defers/enques a function to the next cycle of the (one and only) event loop.
3. All of the above is 100% synchronous and non-premptive, but...
4. Node provides JavaScript hooks to access a shared thread pool in the node process. These hooks are used by the authors of slow io libraries, for example to open files or access disk-based databases.
5. If I need a function to execute asynchronously or ...more precisely... be nonblocking, then I need to make use of that shared thread pool, either by piggybacking on an existing node function which is nonblocking or by learning to use the hooks myself.
Question: Are the hooks exposed in JavaScript, or do I need to write native C code?
The application I have in mind to write does compute-intensive tasks, which is the CPU analog of slow disk.
Thanks!
Consider an upload server that did what you're suggesting:
http.createServer(function (req, res) {
process.nextTick(function () {
var stream = fs.createWriteStream(filename)
req.on("data", function (c) {
// write data to file
stream.write(c)
})
req.on("end", function () {
// request is over
// close file
stream.end()
res.writeHead(200, {})
res.end("got it!")
})
})
}
Because you're not responding to the "request" event synchronously,
you're not guaranteed to be able to attach the "data" event handler
before the first "data" event fires. The parser calls the "onrequest"
function, which emits the "request" event in the server, and then
continues right on through whatever data it has. There is no time to
waste, and you're betting that the body and the headers will never
arrive in the same TCP chunk.
In fact, if you tried to do this in production, you wouldn't *just*
get lots of corrupted files missing their first chunk: since files
smaller than a single packet might be uploaded in one data event, you
might also miss the "end" event, and never send a response! So, users
uploading *small* files would be more likely to see it hang forever
when they try.
.emit("event") is synchronous, always. It's an in-memory operation.
It loops through an array of functions, calling them one after the
other. (Plus some serious optimizations for certain common use
cases.)
.on("event", fn) is synchronous, always. It puts the function in the
list of functions to call when "event" is emitted.
fs.read(..., cb) is asynchronous, always. It schedules the cb to be
called once the IO is completed.
The point is that the server you create with .createServer() (the EventEmitter) .emit()s *asynchronously*, unlike what happens when you call .emit() on an EventEmitter (e.g. on it, on said server).
That's why I pointed to you in my previous email, that .emit() is synchronous ( -> when you call it explicitly) but it's asynchronous when the server returned by .createServer() calls it.
You said: "If an API is synchronous, it must always be synchronous, no exceptions"
And here we have an example of the opposite: the server emits asynchronously, but calling .emit() on it makes it emit synchronously.
--
Jorge.
On 21/01/2012, at 20:25, Isaac Schlueter wrote:
> Jorge,
>
> Consider an upload server that did what you're suggesting:
>
> http.createServer(function (req, res) {
> process.nextTick(function () {
> var stream = fs.createWriteStream(filename)
> req.on("data", function (c) {
> // write data to file
> stream.write(c)
> })
> req.on("end", function () {
> // request is over
> // close file
> stream.end()
> res.writeHead(200, {})
> res.end("got it!")
> })
> })
> }
> <snip>
The application I have in mind to write does compute-intensive tasks, which is the CPU analog of slow disk.
Ah! Thank you. I will check it out.
--
I'm a noob, but I don't see anything wrong by design in letting a function which (synchronously) returns a value also accept a callback which happens to perform asynchronously.
I fail to see why the programmer should be denied this flexibility, which after all is really just syntactic sugar for wrapping the async call not returning a value inside a sync call returning a value. Deny me this, and I will reinvent it.
Am I missing something?
Thanks.
--
I agree that you should be able to write code to whatever API contract you want. But please don't take away my ability to do the same. Regardless of language, anyone can write code that is fragile or breaks.
--
True.
> 1. JavaScript/V8 is single-threaded and never gets prempted.
True, mostly. Your JavaScript program never has to worry about
*another* javascript program tampering with the state of its
JavaScript objects.
However, the contents of a Buffer are stored outside the v8 heap. So,
a function on the thread pool might modify it. The rule of thumb is,
once you pass your buffer to another function, it's not your buffer
any more, so don't touch it.
Also, Isolates introduces the ability for more than a single v8
environment to be running in a single *process*, but they're still
each in a completely separate heap space from one another, so the
semantics of the program don't change much. (I mean, process.pid will
be the same, and process.tid will tell you which thread you're on, but
otherwise, it looks just like a child process.)
> 2. process.nextTick simply defers/enques a function to the next cycle of the
> (one and only) event loop.
True.
> 3. All of the above is 100% synchronous and non-premptive, but...
False. process.nextTick is not synchronous. It happens at the start
of the next tick, not the end of the current one. Most of the time,
that's the same thing, but it's not *guaranteed* to run before
anything else.
> 4. Node provides JavaScript hooks to access a shared thread pool in the node
> process. These hooks are used by the authors of slow io libraries, for
> example to open files or access disk-based databases.
True.
> 5. If I need a function to execute asynchronously or ...more precisely... be
> nonblocking, then I need to make use of that shared thread pool, either by
> piggybacking on an existing node function which is nonblocking or by
> learning to use the hooks myself.
True. Or you can use setTimeout, or process.nextTick, but that won't
run your javascript in parallel, it'll run it *later*. The only way
to run JavaScript in parallel with other JavaScript is as a child
process or Isolate.
> Question: Are the hooks exposed in JavaScript, or do I need to write native
> C code?
You have to write native C code.
> The application I have in mind to write does compute-intensive tasks, which
> is the CPU analog of slow disk.
Use child_process.fork, and communicate with the child via IPC.
// parent.js
var child_process = require("child_process")
var path = require("path")
var child = child_process.fork(path.resolve(__dirname, "child.js"))
child.on("message", function (x) {
if (x === "ping") child.send("pong")
else console.log(x)
})
// child.js
process.on("message", function (x) {
console.log("received: "+x)
process.exit(0)
})
console.log("child starting work")
// some cpu intensive stuff...
for (var i = 0; i < 1e10; i ++) ;
console.log("pinging parent")
process.send("ping")
Jorge, what would it mean for emit to be "asynchronous"? Can you
explain that? I feel like we're passing by one another, and probably
making more confusion in the process.
This is what I mean when I say that emit is synchronous:
var x = 5
foo.on("bar", function () { x = 10 })
foo.emit("bar")
console.log(x) // should be 10
You can still have a synchronous action is scheduled for some later
time, because it's called by something asynchronous.
var x = 5
foo.on("bar", function () { x = 10 })
process.nextTick(function () { foo.emit("bar") }) // or fs or net or whatever
console.log(x) // emit hasn't happened yet. Still 5.
setTimeout(function () { console.log(x) }, 100) // will be 10 later
It's sugar. (Not syntactic sugar, it's API sugar, but I'm hair-splitting.)
var request = createRequest(options, function (response) {
request.whatever(...)
})
// is sugar for:
var request = createRequest(options)
request.on("response", function (response) {
request.whatever(...)
})
Again, none of this is a problem if you make sure that every callback
is guaranteed to be either sync always, or async always.
Thanks Isaac. That's exactly what I meant by sugar.
Callbacks that get an error as the first argument are not events, usually.
I guess you could also say it's sugar for:
createServer(options).on("request", function (request) { ... })
so we just remove the `).on("request"` bit by extending the API
slightly. I guess it does increase size and make for some confusion,
but it's probably too costly to change now.
On Sat, Jan 21, 2012 at 13:48, Mark Hahn <ma...@hahnca.com> wrote:
> I never knew that callbacks were implemented as events. You learn something
> new every day.
>
>
Events happen at any time (asynchronously). A timer, a packet that arrived, a DOM mutation, a click, a keypress, etc.
Events have event listeners that run in response to events.
But the event listeners should not interrupt your code: they should only run when the program flow returns to the event loop.
An async .emit('event') should simply create an event that will be dispatched to its listener(s) as soon as possible, when the program flow returns to the event loop.
A sync .emit('event') goes a step further, and calls the listener(s) instead right on the spot, immediately, interrupting your program flow.
DOM mutation events are synchronous (1)
Async XHRs are botched eventemitters, because the first onreadystatechange event is synchronous but the rest up to readystate === 4 are asynchronous. (2)
DOM Mouse, keyboard, etc events are always asynchronous: they'll never interrupt your code.
(1)
(function () {
var i= 0;
document.body.addEventListener("DOMNodeInserted", function listener () { i++ }, false);
console.log(i);
document.body.appendChild(document.createElement('p'));
document.body.appendChild(document.createElement('p'));
document.body.appendChild(document.createElement('p'));
console.log(i);
})();
Outputs -> 0, 3
(2)
(function () {
var i= 0;
var xhr= new XMLHttpRequest;
xhr.onreadystatechange= function listener () { i++ };
xhr.open('GET', 'nonexistent', true);
xhr.send(null);
console.log(i);
})();
Outputs -> 1
DOM mutation events are synchronous (1)
Async XHRs are botched eventemitters, because the first onreadystatechange event is synchronous but the rest up to readystate === 4 are asynchronous. (2)
DOM Mouse, keyboard, etc events are always asynchronous: they'll never interrupt your code.
On Sun, Jan 22, 2012 at 12:11 PM, Jorge <jo...@jorgechamorro.com> wrote:DOM mutation events are synchronous (1)
Async XHRs are botched eventemitters, because the first onreadystatechange event is synchronous but the rest up to readystate === 4 are asynchronous. (2)
DOM Mouse, keyboard, etc events are always asynchronous: they'll never interrupt your code.
No. All events are synchronous.
XHRs are not botched. The first event occurs immediately because the state changes immediately. The rest occur in the future, when the state has actually changed. The state changes asynchronously, but the events associated with the state change occur synchronously at the time the state changes.
DOM Mouse, keyboard, etc. events are always synchronous. They never interrupt your code because the actions a user takes don't occur while your code is running.
<snip>
--
> I completely fail to see your reasoning for either of the cases below. Neither code block below introduces any new arguments or reasoning to this conversation. They're merely slight changes to previous blocks of code, with the addition of known infinitely blocking code blocks.
You said:
>> DOM Mouse, keyboard, etc. events are always synchronous. They never interrupt your code because the actions a user takes don't occur while your code is running.
If you were right, this code:
> (function () {
> var i= 0;
> window.onclick= window.onkeyup= function listener () { i++ };
> while (i === 0) ;
> })();
would only block until a click or a keyup, but it blocks forever, because mouse and keyboard events never interrupt your code.
You said:
>> XHRs are not botched. The first event occurs immediately because the state changes immediately. The rest occur in the future, when the state has actually changed. The state changes asynchronously, but the events associated with the state change occur synchronously at the time the state changes.
If that were true, this:
> (function () {
> var i= 0;
> var xhr= new XMLHttpRequest;
> xhr.onreadystatechange= function listener () { i++ };
> xhr.open('GET', 'nonexistent', true);
> xhr.send(null);
> while (i === 1) ;
> })();
would only block until "the future, when the state has actually changed", but it blocks forever, because *only* the first readystatechange event is synchronous (interrupts your code).
--
Jorge.
--
Jorge.
Saying that mouse events are synchronous seems a bit far-fetched. From
a human observer's standpoint, the mouse actions are truly
asynchronous (the user is free to decide when he clicks). From the
event loop's standpoint, the dispatching of events is a synchronous
operation.
> I said "they never interrupt your code". What is so confusing about this?
You said more than that:
"They never interrupt your code because the actions a user takes don't occur while your code is running"
Then I sent you a code snippet in which the user actions *do* occur while your code is running, to demonstrate that the reason why these listeners never interrupt your code is *not* that the events "don't occur while your code is running".
DOM mutation events happen while your code is running, and their listeners interrupt your code.
DOM Mouse, keyboard, etc events (may) happen (as well) while your code is running, but their listeners won't ever interrupt your code
> <snip>
--
Jorge.
On 27/01/2012, at 13:44, Scott González wrote:You said more than that:
> I said "they never interrupt your code". What is so confusing about this?
"They never interrupt your code because the actions a user takes don't occur while your code is running"
Then I sent you a code snippet in which the user actions *do* occur while your code is running, to demonstrate that the reason why these listeners never interrupt your code is *not* that the events "don't occur while your code is running".
DOM mutation events happen while your code is running, and their listeners interrupt your code.
DOM Mouse, keyboard, etc events (may) happen (as well) while your code is running, but their listeners won't ever interrupt your code
I don't really know how node knows when to run a function asynchronously or not.
Let's say you have this piece of code.
function gen_url(str) {
return 'http://' + str;
}
full_url = gen_url('www.google.com');
In that case I'm obviously counting on the function gen_url being executed synchronously.
Now If I have
function hit_mysql(query, callback) {
var mystuff = oldstuff * system_variable;
client = require('mysql').Client();
client.query(query, callback);
}
var one = 'one';
hit_mysql('select ...', function(){console.log('done');});
var two = 'two';
I would expect hit_mysql to run asynchronousy.
How does node figure this out? I'm no "marking" any function as "sync" or "async". Does node througfuly examine the function's body to see if somewhere in the function body (or in the body of the functions defined in the function body) there is some well recognized native node async call, like setTimeout, or http.listen(), or whatever?
--
uh, oh.
Pardon for resurrecting such old thread but I have a question about process.nextTick: why/how does it eliminate the current stack? What happens behind the scenes?
Ok, I think I'm thinking about process.nextTick as it was in node <0.10, where, if I'm not mistakenfunction f() {process.nextTick(f)}
f()would loop infinitely, whereas an immediate recursive call throws RangeError.I tried running that in v0.10 and got RangeError. However,function f() {setImmediate(f)}
f()puts the function in "background" and makes node process consume 100% CPU. What happens there?
On Friday, November 8, 2013 5:20:21 PM UTC-5, Rick Waldron wrote:On Fri, Nov 8, 2013 at 3:57 PM, Ilya Shaisultanov <ilya.sha...@gmail.com> wrote:
Pardon for resurrecting such old thread but I have a question about process.nextTick: why/how does it eliminate the current stack? What happens behind the scenes?
It doesn't eliminate the current stack. The callback is "scheduled" and subsequently executed in the next execution turn.Rick
--
--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to
nodejs+un...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en
---
You received this message because you are subscribed to the Google Groups "nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.