I would like to clarify - when is it correct to use setImmediate for a node callback.
The examples/articles I've studied argue it is best to use setImmediate to ensure a callback is asynchronous. The most common example is where a value might exist in a "cache" e.g.
const getData = function(id,callback) {
const cacheValue = cache[id];
if (cacheValue) {
// DON'T DO THIS ...
return callback(null,cacheValue);
// DO THIS ...
return setImmediate(callback,null,cacheValue);
}
return queryDB(id,function(err,result){
if (err){
return callback(err);
}
return callback(null,result);
});
};
Here's where it gets confusing. Most node examples of error handing in callbacks never seem to call setImmediate. From my example above:
if (err) {
return callback(err);
}
instead of:
if (err) {
return setImmediate(callback,err);
}
I read some arguments that say that setImmediate is not necessary in this case and indeed can impact performance, why is this? Is this example not the same as the example of accessing the cache.
Is it better to be consistent and always use setImmediate? In which case then, why not do the following:
const getData = function(id,callback) {
const cacheValue = cache[id];
if (cacheValue) {
return setImmediate(callback,null,cacheValue);
}
return queryDB(id,function(err,result){
if (err){
return setImmediate(callback,err);
}
return setImmediate(callback,null,result);
});
};
Quick answer
If you're calling the callback synchronously (before the host function has returned), you should use setImmediate(). If you are calling the callback asynchronously (after the function has returned), you do not need it and can call the callback directly.
Longer Answer
When you have an interface that accepts a callback and that callback is at least sometimes called asynchronously (meaning some indefinite time in the future after your function has returned), then it is a good practice to always call it asynchronously, even if the result is known immediately. This is so that the caller of your function and user of the callback will always see a consistent asynchronous interface.
As you seem aware of, a classic example of this would be with a cached result. If the result is in the cache, then the result is known immediately.
There is no law of Javascript-land that one MUST always call the callback asynchronously. Code may work OK if the callback is sometimes called synchronously and sometimes called asynchronously, but it is more subject to bugs caused by how the callback is used. If the callback is always called asynchronously, then the caller is less likely to accidentally create a bug by how they use the callback.
In the case of:
if (err) {
return callback(err);
}
My guess is that this is already in an asynchronous location. For example:
function someFunction(someUrl, callback) {
request(someURL, function(response, body, err) {
// this is already inside an async response
if (err) {
callback(err);
} else {
callback(body);
}
});
}
I read some arguments that say that setImmediate is not necessary in this case and indeed can impact performance, why is this? Is this example not the same as the example of accessing the cache.
In this case, the if (err) is already in an asynchronous callback part of code so there is no need for an additional setImmediate() there. The host function has already returned and thus calling the callback here without setImmediate() is already asynchronous timing. There is no need for an additional setImmediate().
The only time the setImmediate() is needed is when you are still in the synchronous body of the function and calling the callback there would call it before the host function returns, thus making the callback synchronous instead of asynchronous.
Summary
When is setImmediate required in node callback
So, to summarize. You should use setImmediate(callback) when you in code that is executing synchronously before the host function has returned. You do not need to use setImmediate(callback) when the code you are in is already in an asynchronous callback and the host function has already returned.
FYI, this is one reason to exclusively use promises in your asynchronous programming interfaces (instead of plain callbacks) because promises already handle this for you automatically. They guarantee that a .then() handler on a resolved promise will always be called asynchronously, even if the promise is resolved synchronously.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With