简体   繁体   English

实现node.js回调的超时

[英]Implementing timeouts for node.js callbacks

This is a typical situation in node.js: 这是node.js中的典型情况:

asyncFunction(arguments, callback);

When asynFunction completes, callback gets called. asynFunction完成时,将调用callback A problem I see with this pattern is that, if asyncFunction never completes (and asynFunction doesn't have a built-in time-out system) then callback will never be called. 我看到这个模式的一个问题是,如果asyncFunction 永远不会完成(并且asynFunction没有内置的超时系统),那么永远不会调用callback Worse, it seems that callback has no way of determining that asynFunction will never return. 更糟糕的是,似乎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. 我想实现一个“超时”,由此,如果callback尚未调用由asyncFunction 1秒钟之内,那么callback会自动被调用,并假设asynFunction已经出错了。 What is the standard way of doing this? 这样做的标准方法是什么?

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

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

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

DEMO DEMO

But note the following: 但请注意以下事项:

  • The timeout is started immediately when you call ensureExecution , so you cannot cache that function reference. 当您调用ensureExecution ,会立即启动超时,因此您无法缓存该函数引用。

  • The arguments passed to the callback will differ. 传递给回调的参数会有所不同。 For example asyncFunction might pass some arguments to callback upon success, but if the function is called by the timeout, no arguments will be passed. 例如, asyncFunction可能会在成功时将一些参数传递给callback ,但如果超时调用该函数,则不会传递任何参数。 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); //... } 

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. 我遇到了同样的问题,内容脚本尝试在BG扩展准备好之前打开BG扩展上的端口。 A work around was to wait for the BG extension to reply to a message and repeat this till successful. 解决方法是等待BG扩展程序回复消息并重复此操作直到成功。 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 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毫秒延迟后。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM