I was reading this article on howtonode,
but don't get why it's fake async ?
So fake async is described as:
function asyncFake(data, callback) {
if(data === 'foo') callback(true);
else callback(false);
}
asyncFake('bar', function(result) {
// this callback is actually called synchronously!
});
Correct code: always async
function asyncReal(data, callback) {
process.nextTick(function() {
callback(data === 'foo');
});
}
My question is what's wrong with the first part of code ?
Why nextTick() can promise the 'right' effect ?...
Please explain to me. Thanks.
Nothing's wrong with the first case. However, it's just that you have to be proactive (as the developer) to know exactly what's happening in your code.
In the first case, you are not doing any I/O, and the callback is not actually being put into the Event Loop. It just the same as doing this:
if(data === 'foo')
return true;
else
return false;
However, in second case, you are putting the callback into the event loop until the next iteration.
In terms of how things work, nothing's wrong. However, you need to be aware of what implications are.
For instance:
function maybeSync(a, cb) {
if(a === 'a') {
cb('maybeSync called');
} else {
// put the called into event-loop for the next iteration
process.nextTick(function() {
cb('maybeSync called');
});
}
}
function definitelySync() {
console.log('definitelySync called');
}
someAsync('a', function(out) {
console.log(out);
});
definitelySync();
In the top case, which one gets called first?
If the input is "a" then the output is:
maybeSync called
definitelySync called
If the input is something else (e.g. not "a") then the output would be:
definitelySync called
maybeSync called
You need to make them consistent, as it would be easy to distinguish if the callback can be called sync/async based on the condition. Again comes back to being responsible, being consistent and being aware of what's happening in your code. =)
In the async fake function - you can see that callback is called as a normal function invocation i.e in the same call stack.
someone calls async fake fn
async fake fn calls the callback passed to it
If that callback takes time to complete - the async fake fn is kept waiting i.e it remains in call stack.
By using process tick - we are just submitting the callback function to be scheduled for execution.
This process tick call completes immediately and the asyncreal will return immediately. Thus the callback will be executed in asynchronous way.
Related
I'm struggling with callbacks in Node.js. I simply want playerNumber to be set to the number of players in my collection of Players. The console.log works, but I can't get the variable out of the function and into the playerNumber variable.
And if there's a simpler way get this value for use in the rest of my backend code, I'm all ears. I'm clearly new at Node.js, but the code always seems more involved than I'm expecting.
Thanks in advance!
var playerNumber = function countPlayers(callback){
Player.count(function(err, numOfDocs) {
console.log('I have '+numOfDocs+' documents in my collection');
callback(err, numOfDocs);
});
}
It's probably async, and it's a typical first-timer experience to want to "get back to normal" on the call chain on the way back from async call. This can't be done, but it's not so bad to live with it. Here's how...
Step 1: Promises are better than callbacks. I'll leave the long story
to others.
Step 2: Callbacks can be made into promises
In the OP case...
// The promise constructor takes a function that has two functions as params
// one to call on success, and one to call on error. Instead of a callback
// call the 'resolve' param with the data and the 'reject' param with any error
// mark the function 'async' so callers know it can be 'await'-ed
const playerNumber = async function countPlayers() {
return new Promise((resolve, reject) => {
Player.count(function(err, numOfDocs) {
err ? reject(err) : resolve(numOfDocs);
});
});
}
Step 3: Yes, the callers must deal with this, and the callers of the callers, and so on. It's not so bad.
In the OP case (in the most modern syntax)...
// this has to be async because it 'awaits' the first function
// think of await as stopping serial execution until the async function finishes
// (it's not that at all, but that's an okay starting simplification)
async function printPlayerCount() {
const count = await playerNumber();
console.log(count);
}
// as long as we're calling something async (something that must be awaited)
// we mark the function as async
async function printPlayerCountAndPrintSomethingElse() {
await printPlayerCount();
console.log('do something else');
}
Step 4: Enjoy it, and do some further study. It's actually great that we can do such a complex thing so simply. Here's good reading to start with: MDN on Promises.
I wrote the following function that takes a callback. I always thought that the content of a callback might be executed later. In this case it doesn't...
doesSomething(function(){
console.log("1");
var i = 0;
while (i < 10000)
{
console.log("hello");
i = i + 1;
}
});
console.log("2");
console.log("3");
Whatever I do, "2" and "3" always comes after "1" and a thousand of "hello".
Like this:
1
hello
hello
...
hello
hello
2
3
What I thought it would do:
2
3
1
hello
hello
...
hello
hello
Even if this behaviour makes my life simpler I don't really understand why the execution is procedural.
Do you think that in some case it might go reverse ?
It all depends upon how doSomething() calls its callback. If it calls the callback synchronously (e.g. before it returns), then everything in that function will execute before doSomething() returns. If it calls it asynchronously (sometime after it returns), then you will get a different order.
So, the order is determined by the code that you do not show us in doSomething().
Based on the order you observe, doSomething() must be calling its callback synchronously and thus it will execute in order just like any other synchronous function call.
For example, here are two scenarios:
function doSomething(callback) {
callback();
}
This calls the callback passed to it synchronously and thus it will execute before doSomething() returns and thus it will execute before code that follows.
Whereas something like this;
function doSomething(callback) {
fs.writeFile('foo.txt', callback);
}
or:
function doSomething(callback) {
setTimeout(callback, 50);
}
Will execute the callback asynchronously sometime later after the function has already returned and you will see a different execution order with your console.log() statements.
From the output that you mention, I can say that there is nothing asynchronous happening in your code inside doesSomething and is probably looking like this:
function doesSomething(callback) {
<maybe some synchronous operations, e.g. no ajax or filesystem calls>
callback();
}
, so the order of the calling functions will be always the same, like you posted above:
doesSomething(callback)
console.log(2)
console.log(3)
If you want the order you mention you should call them like this:
console.log(2)
console.log(3)
doesSomething(callback)
This does not have to do something with node.js in particular. It is the way methods are executed in JavaScript, which is synchronous since it is single threaded.
When you call the method doesSomething(callback) it immediately executes it and nothing else until it completes
javascript is a single threaded language, but not the node.js runtime or the browser. There are certain functions provided by node.js or the browser that would trigger for a function to be assigned to a task queue to be processed in a separate thread
lets take your example and make dosomething async
this is your synchronous code that would print, 1 hello...,2,3
function doesSomething(callback) {
callback();
}
doesSomething(function(){
console.log("1");
var i = 0;
while (i < 3)
{
console.log("hello");
i = i + 1;
}
});
console.log("2");
console.log("3");
and this is the async code, that prints out 3, 2, 1, hello ...
function doesSomething(callback) {
setTimeout(callback, 0);
}
doesSomething(function(){
console.log("1");
var i = 0;
while (i < 3)
{
console.log("hello");
i = i + 1;
}
});
console.log("2");
console.log("3");
to explain why the second code is async, you have to understand that setTimeout is not part of javascript, its an api provided by node.js and the browsers. setTimeout puts the callback function into a queue to be processed. At this time a separate thread runs the setTimeout and when the timer ends it puts the callback into a callback queue, and when the call stack is clear, whatever is in the callback queue will be moved to the call stack and processed.
in node you can use process.nextTick(yourFunction); to make it async, this is just another function that nodejs provides you which is better than using setTimeout (which I wont get into here) you can checkout https://howtonode.org/understanding-process-next-tick to understand more about process.nextTick
for more info check out this video https://youtu.be/8aGhZQkoFbQ?t=19m25s
I have the node.js code running on a server and would like to know if it is blocking or not. It is kind of similar to this:
function addUserIfNoneExists(name, callback) {
userAccounts.findOne({name:name}, function(err, obj) {
if (obj) {
callback('user exists');
} else {
// Add the user 'name' to DB and run the callback when done.
// This is non-blocking to here.
user = addUser(name, callback)
// Do something heavy, doesn't matter when this completes.
// Is this part blocking?
doSomeHeavyWork(user);
}
});
};
Once addUser completes the doSomeHeavyWork function is run and eventually places something back into the database. It does not matter how long this function takes, but it should not block other events on the server.
With that, is it possible to test if node.js code ends up blocking or not?
Generally, if it reaches out to another service, like a database or a webservice, then it is non-blocking and you'll need to have some sort of callback. However, any function will block until something (even if nothing) is returned...
If the doSomeHeavyWork function is non-blocking, then it's likely that whatever library you're using will allow for some sort of callback. So you could write the function to accept a callback like so:
var doSomHeavyWork = function(user, callback) {
callTheNonBlockingStuff(function(error, whatever) { // Whatever that is it likely takes a callback which returns an error (in case something bad happened) and possible a "whatever" which is what you're looking to get or something.
if (error) {
console.log('There was an error!!!!');
console.log(error);
callback(error, null); //Call callback with error
}
callback(null, whatever); //Call callback with object you're hoping to get back.
});
return; //This line will most likely run before the callback gets called which makes it a non-blocking (asynchronous) function. Which is why you need the callback.
};
You should avoid in any part of your Node.js code synchronous blocks which don't call system or I/O operations and which computation takes long time (in computer meaning), e.g iterating over big arrays. Instead move this type of code to the separate worker or divide it to smaller synchronous pieces using process.nextTick(). You can find explanation for process.nextTick() here but read all comments too.
I've been using the Q module to implement promises on a project I'm working on.
I'm using the static method Q.fncall() to create a promise out of a node.js style function (based on callbacks returning err,result).
The problem is that I need to stop the execution of said function after a certain amount of time, so I used the function "timeout" of the Q module. So, after x amount of time, the "error" callback on the done function executes and let's me handle the timeout but the function itself keeps getting executed until it reaches its final callback even if the handler is not listening anymore.
The question is: Is there any way to stop the execution of a function after the timeout is executed? I know I can just set a variable on the timeout handler and keep checking in the function if the timeout is over, but I'm hoping for a cleaner way of achieving this.
The code is as follows:
Q.nfcall(test1, id)
.timeout(1000)
.done(
function (value) {
console.log("SUCCESS: " + value);
},
function (reason) {
console.log("ERROR " + reason);
},
function (progress) {
console.log("PROGRESS " + progress);
}
);
And the test1 function:
function test1(id,callback){
db_rw_pool.query("SELECT * FROM table WHERE id=?",[id], function(err,result) {
if(err){
callback(err,null);
}
else {
setTimeout(function(){
console.log("I DON'T WANT YOU TO BRE PRINTED")
callback(null,result);
},2000);
}
return;
});
}
In my ideal situation, the code inside setTimeout(...,2000) should never be executed. Is this possible?
Thanks in advance.
I think you're concerning yourself over a too low level. Once you've ran test1, there's no way to stop db_rw_pool.query from executing, and its callback from being called (unless you'd take special precautions in this db_rw_pool.query method). The results for the SQL query WILL come back. The question is whether the code will swallow these results at some point, or not. The swallowing in this case happens in the code for Q's timeout method. Just place any code you don't want to be executed in the onFulfilled handler of done.
You write
The problem is that I need to stop the execution of said function after a certain amount of time, so I used the function "timeout" of the Q module.
The timeout method won't stop this function from executing. Rather, it returns a new promise that is instructed to fail if the promise it's bound to (the one which you've made with Q.nfcall) is not fulfilled within the set period (1000 ms in this case).
If you somehow want to stop a callback from executing, you could wrap it inside a function that checks for the time. Something like:
function stopExecutingAfter(timeout, fn) {
var stopifAfter = Date.now() + timeout
return function() {
if(Date.now() > stopIfAfter) return
fn.apply(null, arguments)
}
}
Q mainly concerns itself with promises, so it's obvious that it won't do this for you.
Using this technique, you could make a nfcallWithTimeout function that returns a promise while protecting the passed function (by wrapping it in something like the above) as well. Then you don't have to configure the timeout behavior twice.
Consider using another language because there is no way to do this in Javascript.
I have the following example code - the first part can result in an async call or not - either way it should continue. I cannot put the rest of the code within the async callback since it needs to run when condition is false. So how to do this?
if(condition) {
someAsyncRequest(function(error, result)) {
//do something then continue
}
}
//do this next whether condition is true or not
I assume that putting the code to come after in a function might be the way to go and call that function within the async call above or on an else call if condition is false - but is there an alternative way that doesn't require me breaking it up in functions?
A library I've used in Node quite often is Async (https://github.com/caolan/async). Last I checked this also has support for the browser so you should be able to npm / concat / minify this in your distribution. If you're using this on server-side only you should consider https://github.com/continuationlabs/insync, which is a slightly improved version of Async, with some of the browser support removed.
One of the common patterns I use when using conditional async calls is populate an array with the functions I want to use in order and pass that to async.waterfall.
I've included an example below.
var tasks = [];
if (conditionOne) {
tasks.push(functionOne);
}
if (conditionTwo) {
tasks.push(functionTwo);
}
if (conditionThree) {
tasks.push(functionThree);
}
async.waterfall(tasks, function (err, result) {
// do something with the result.
// if any functions in the task throws an error, this function is
// immediately called with err == <that error>
});
var functionOne = function(callback) {
// do something
// callback(null, some_result);
};
var functionTwo = function(previousResult, callback) {
// do something with previous result if needed
// callback(null, previousResult, some_result);
};
var functionThree = function(previousResult, callback) {
// do something with previous result if needed
// callback(null, some_result);
};
Of course you could use promises instead. In either case I like to avoid nesting callbacks by using async or promises.
Some of the things you can avoid by NOT using nested callbacks are variable collision, hoisting bugs, "marching" to the right > > > >, hard to read code, etc.
Just declare some other function to be run whenever you need it :
var otherFunc = function() {
//do this next whether condition is true or not
}
if(condition) {
someAsyncRequest(function(error, result)) {
//do something then continue
otherFunc();
}
} else {
otherFunc();
}
Just an another way to do it, this is how I abstracted the pattern. There might be some libraries (promises?) that handle the same thing.
function conditional(condition, conditional_fun, callback) {
if(condition)
return conditional_fun(callback);
return callback();
}
And then at the code you can write
conditional(something === undefined,
function(callback) {
fetch_that_something_async(function() {
callback();
});
},
function() {
/// ... This is where your code would continue
});
I would recommend using clojurescript which has an awesome core-async library which makes life super easy when dealing with async calls.
In your case, you would write something like this:
(go
(when condition
(<! (someAsyncRequest)))
(otherCodeToHappenWhetherConditionIsTrueOrNot))
Note the go macro which will cause the body to run asynchronously, and the <! function which will block until the async function will return. Due to the <! function being inside the when condition, it will only block if the condition is true.