实现node.js回调的超时

时间:2011-12-04 18:58:20

标签: javascript node.js asynchronous

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

asyncFunction(arguments, callback);

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

我想实现"超时"如果{1}}在1秒内没有调用asynFunction,那么callback会自动调用,假设asyncFunction出错了。这样做的标准方法是什么?

4 个答案:

答案 0 :(得分:23)

我不熟悉任何执行此操作的库,但是自己连接起来并不困难。

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

答案 1 :(得分:7)

您可能需要提出自己的解决方案。像

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

答案 2 :(得分:4)

你可以这样做:

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时,会立即开始超时,因此您无法缓存该功能参考。

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

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

答案 3 :(得分:1)

我遇到了同样的问题,内容脚本尝试在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 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});
    }
  });

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