Implementing timeouts for node.js callbacks
Solution 1
I'm not familiar with any libraries that do this, but it's not hard to wire up yourself.
// Setup the timeout handler
var timeoutProtect = setTimeout(function() {
// Clear the local timer variable, indicating the timeout has been triggered.
timeoutProtect = null;
// Execute the callback with an error argument.
callback({error:'async timed out'});
}, 5000);
// Call the async function
asyncFunction(arguments, function() {
// Proceed only if the timeout handler has not yet fired.
if (timeoutProtect) {
// Clear the scheduled timeout handler
clearTimeout(timeoutProtect);
// Run the real callback.
callback();
}
});
Solution 2
You could do something like this:
function ensureExecution(func, timeout) {
var timer, run, called = false;
run = function() {
if(!called) {
clearTimeout(timer);
called = true;
func.apply(this, arguments);
}
};
timer = setTimeout(run, timeout);
return run;
}
Usage:
asyncFunction(arguments, ensureExecution(callback, 1000));
But note the following:
The timeout is started immediately when you call
ensureExecution
, so you cannot cache that function reference.-
The arguments passed to the callback will differ. For example
asyncFunction
might pass some arguments tocallback
upon success, but if the function is called by the timeout, no arguments will be passed. You have to keep that it mind. You could also provide default arguments with which the function should be called in this case:function ensureExecution(func, timeout, args, this_obj) { // ... timer = setTimeout(function() { run.apply(this_obj, args); }, timeout); //... }
Solution 3
I ran into the same problem with a content script trying to open the port on the BG extension before the BG extension was ready. A work around was to wait for the BG extension to reply to a message and repeat this till successful. Here are the code snippets.
Content Script:
var nTimes = 10;
var bIsReady = false;
checkBGReady();
function checkBGReady() {
if (!bIsReady) {
chrome.runtime.sendMessage({msgText: "hello "+nTimes}, function(response) {
if (response && response.ack) {
console.log("have response:"+response.ack+" "+nTimes);
bIsReady = true;
// continue with initialization
bootStrap(sURL);
checkReady();
} else {
console.log("have no ack response %o",response);
}
});
}
nTimes -= 1;
if (nTimes > 0 && !bIsReady) {
setTimeout(checkBGReady,100);
}
}
BG Extension
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log(sender.tab ?"from a content script:" + sender.tab.url :"from the extension");
if (request.msgText) {
console.log("Have msg "+request.msgText);
sendResponse({ack: "have contact "+request.msgText});
}
});
In my case it usually took after the first 100ms delay.
Randomblue
Updated on June 18, 2022Comments
-
Randomblue almost 2 years
This is a typical situation in node.js:
asyncFunction(arguments, callback);
When
asynFunction
completes,callback
gets called. A problem I see with this pattern is that, ifasyncFunction
never completes (andasynFunction
doesn't have a built-in time-out system) thencallback
will never be called. Worse, it seems thatcallback
has no way of determining thatasynFunction
will never return.I want to implement a "timeout" whereby if
callback
has not been called byasyncFunction
within 1 second, thencallback
automatically gets called with the assumption thatasynFunction
has errored out. What is the standard way of doing this?