javascript 为 node.js 回调实现超时
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8377777/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Implementing timeouts for node.js callbacks
提问by Randomblue
This is a typical situation in node.js:
这是 node.js 中的典型情况:
asyncFunction(arguments, callback);
When asynFunction
completes, callback
gets called. A problem I see with this pattern is that, if asyncFunction
nevercompletes (and asynFunction
doesn't have a built-in time-out system) then callback
will never be called. Worse, it seems that callback
has no way of determining that asynFunction
will never return.
当asynFunction
完成,callback
被调用。我看到这种模式的一个问题是,如果asyncFunction
永远不会完成(并且asynFunction
没有内置超时系统),那么callback
永远不会被调用。更糟糕的是,似乎callback
无法确定asynFunction
永远不会回来。
I want to implement a "timeout" whereby if callback
has not been called by asyncFunction
within 1 second, then callback
automatically gets called with the assumption that asynFunction
has errored out. What is the standard way of doing this?
我想实现一个“超时”,如果在 1 秒内callback
没有被调用asyncFunction
,那么在错误callback
的假设下自动被调用asynFunction
。这样做的标准方法是什么?
采纳答案by Alex Wayne
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();
}
});
回答by Alex Wayne
You probably need to come out with a solution of your own. Like
您可能需要提出自己的解决方案。喜欢
function callBackWithATimeout (callback, timeout) {
var run, timer;
run = function () {
if (timer) {
clearTimeout(timer);
timer = null;
callback.apply(this, arguments);
}
};
timer = setTimeout(run, timeout, "timeout");
return run;
}
and then
接着
asyncFunction(arguments, callBackWithATimeout(callback, 2000));
回答by Felix Kling
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); //... }
调用时会立即开始超时
ensureExecution
,因此您无法缓存该函数引用。传递给回调的参数会有所不同。例如,
asyncFunction
可能会callback
在成功时传递一些参数,但如果该函数被超时调用,则不会传递任何参数。你必须牢记这一点。您还可以提供在这种情况下调用函数的默认参数:function ensureExecution(func, timeout, args, this_obj) { // ... timer = setTimeout(function() { run.apply(this_obj, args); }, timeout); //... }
回答by user3417987
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.
我遇到了同样的问题,内容脚本试图在 BG 扩展准备好之前打开 BG 扩展上的端口。解决方法是等待 BG 扩展回复消息并重复此操作直到成功。这是代码片段。
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
BG 扩展
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.
就我而言,它通常在第一个 100 毫秒延迟之后进行。