为node.jscallback实现超时

这是node.js中的典型情况:

asyncFunction(arguments, callback); 

asynFunction完成时, callback被调用。 我用这种模式看到的一个问题是,如果asyncFunction 从不完成(并且asynFunction没有内置的超时系统),那么callback将永远不会被调用。 更糟糕的是,似乎callback没有办法确定asynFunction将永远不会返回。

我想实现一个“超时”,如果在1秒内没有被asyncFunction调用callback asyncFunction ,那么callback自动被调用,假设asynFunction出错了。 这样做的标准方式是什么?

我不熟悉任何这样做的库,但是你自己编写并不难。

 // 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(); } }); 

你可能需要提出一个你自己的解决scheme。 喜欢

 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; } 

接着

 asyncFunction(arguments, callBackWithATimeout(callback, 2000)); 

你可以做这样的事情:

 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; } 

用法:

 asyncFunction(arguments, ensureExecution(callback, 1000)); 

DEMO

但请注意以下几点:

  • 当您调用ensureExecution ,超时会立即启动,因此您无法caching该函数引用。

  • 传递给callback的参数将有所不同。 例如, asyncFunction在成功时可能会传递一些参数给callback ,但是如果函数被超时调用,则不会传递参数。 你必须记住它。 在这种情况下,您还可以提供用于调用函数的默认参数:

     function ensureExecution(func, timeout, args, this_obj) { // ... timer = setTimeout(function() { run.apply(this_obj, args); }, timeout); //... } 

我遇到了同样的问题,在BG分机准备就绪之前,尝试打开BG分机上的端口。 解决方法是等待BG分机回复消息并重复此操作直到成功。 这里是代码片段。

内容脚本:

 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扩展

  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}); } }); 

在我的情况下,通常在第一个100毫秒延迟之后。