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.
Related
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 understand what a callback is and what asynchronous means, what I don't get is how to run asynchronous functions in node.
For example, how is this
var action = (function(data,callback) {
result = data+1;
callback(result);
});
http.createServer(function (req, res) {
action(5, function(r){
res.end(r.toString());
});
}).listen(80);
different from this
var action = (function(data) {
result = data+1;
return result;
});
http.createServer(function (req, res) {
var r = action(5);
res.end(r.toString());
}).listen(80);
?
I guess in the first example I'm doing it asynchronously, yet I don't know how Node knows when to do it sync or async... is it a matter of the return? or the fact that in the sync mode we're doing var x = func(data);?
And also: when to use sync or async? Because obviously you don't want to use it when adding +1... is it OK to use async just when performing IO tasks, such as reading from DB?
For example, I'm using the library crypto to encrypt a short string (50 chars at most), is this case a good example where I should already be using async?
I guess in the first example I'm doing it asynchronously...
Your first example isn't async :) Merely passing a callback and calling it when you're done doesn't make a function asynchronous.
Asynchronous means that, basically, you're telling Node: "here, do this for me, and let me know when you're done while I continue doing other stuff".
Your example is not handing anything to Node for future completion. It's doing a calculation and calling the callback immediately after that. That's functionally the same as your second example, where you return the result of the calculation.
However, you can change your first example to something that is asynchronous:
var action = (function(data,callback) {
setTimeout(function() {
result = data + 1;
callback(result);
}, 1000);
});
Here, you're telling Node to delay calling the callback for one second, by using setTimeout. In the mean time, Node won't get stuck waiting for a second; it will happily accept more HTTP requests, and each one will be delayed one second before the response is sent.
When to use sync or async?
Asynchronous code is "viral": if you rely on functions that are async, your own code that uses those functions will also have to be async (generally by accepting a callback, or using another mechanism to deal with asynchronicity, like promises).
For example, I'm using the library crypto to encrypt a short string (50 chars at most), is this case a good example where I should already be using async?
This depends on which function you're using. AFAIK, most encryption functions in crypto aren't asynchronous, so you can't "make" them asynchronous yourself.
Both examples will work synchronous. Simple async operations are setTimout and setInterval.
Node actually doesn't care what code are you running. You can block or not (blocking/non-blocking).
In other words - you have event loop. If your process is async he will pass the program control to the event loop, so it can execute any other action node needs to be done. If not - he wont.
if you want a function to work asynchronously, you can do that using promises, look at the code below :
function is_asynch(){
return new Promise((resolve,reject)=>{
resolve( here_your_synch_function() )
})
}
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.
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.
mongoosejs async code .
userSchema.static('alreadyExists',function(name){
var isPresent;
this.count({alias : name },function(err,count){
isPresent = !!count
});
console.log('Value of flag '+isPresent);
return isPresent;
});
I know isPresent is returned before the this.count async function calls the callback , so its value is undefined . But how do i wait for callback to change value of isPresent and then safely return ?
what effect does
(function(){ asynccalls() asynccall() })(); has in the async flow .
What happens if var foo = asynccall() or (function(){})()
Will the above two make return wait ?
can process.nextTick() help?
I know there are lot of questions like these , but nothing explained about problem of returning before async completion
There is no way to do that. You need to change the signature of your function to take a callback rather than returning a value.
Making IO async is one of the main motivation of Node.js, and waiting for an async call to be completed defeats the purpose.
If you give me more context on what you are trying to achieve, I can give you pointers on how to implement it with callbacks.
Edit: You need something like the following:
userSchema.static('alreadyExists',function (name, callback) {
this.count({alias : name}, function (err, count) {
callback(err, err ? null : !!count);
console.log('Value of flag ' + !!count);
});
});
Then, you can use it like:
User.alreadyExists('username', function (err, exists) {
if (err) {
// Handle error
return;
}
if (exists) {
// Pick another username.
} else {
// Continue with this username.
}
}
Had the same problem. I wanted my mocha tests to run very fast (as they originally did), but at the same time to have a anti-DOS layer present and operational in my app. Running those tests just as they originally worked was crazy fast and ddos module I'm using started to response with Too Many Requests error, making the tests fail. I didn't want to disable it just for test purposes (I actually wanted to have automated tests to verify Too Many Requests cases to be there as well).
I had one place used by all the tests that prepared client for HTTPS requests (filled with proper headers, authenticated, with cookies, etc.). It looked like this more or less:
var agent = thiz.getAgent();
thiz.log('preReq for user ' + thiz.username);
thiz.log('preReq for ' + req.url + ' for agent ' + agent.mochaname);
if(thiz.headers) {
Object.keys(thiz.headers).map(function(header) {
thiz.log('preReq header ' + header);
req.set(header, thiz.headers[header]);
});
}
agent.attachCookies(req);
So I wanted to inject there a sleep that would kick in every 5 times this client was requested by a test to perform a request - so the entire suite would run quickly and every 5-th request would wait to make ddos module consider my request unpunishable by Too Many Requests error.
I searched most of the entries here about Async and other libs or practices. All of them required going for callback - which meant I would have to re-write a couple of hundreds of test cases.
Finally I gave up with any elegant solution and fell to the one that worked for me. Which was adding a for loop trying to check status of non-existing file. It caused a operation to be performed long enough I could calibrate it to last for around 6500 ms.
for(var i = 0; i < 200000; ++i) {
try {
fs.statSync('/path' + i);
} catch(err) {
}
};