Реализация таймаутов для обратных вызовов node.js - PullRequest
29 голосов
/ 04 декабря 2011

Это типичная ситуация в node.js:

asyncFunction(arguments, callback);

Когда asynFunction завершается, вызывается callback. Проблема, которую я вижу с этим шаблоном, заключается в том, что, если asyncFunction никогда не завершится (а asynFunction не имеет встроенной системы тайм-аута), то callback никогда не будет вызван. Хуже того, кажется, что callback не может определить, что asynFunction никогда не вернется.

Я хочу реализовать «тайм-аут», при котором если callback не был вызван asyncFunction в течение 1 секунды, то callback автоматически вызывается с предположением, что asynFunction произошла ошибка. Каков стандартный способ сделать это?

Ответы [ 4 ]

23 голосов
/ 04 декабря 2011

Я не знаком ни с какими библиотеками, которые делают это, но нетрудно подключить себя.

// 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();
  }
});
7 голосов
/ 04 декабря 2011

Вам, вероятно, нужно найти собственное решение.Как

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));
4 голосов
/ 04 декабря 2011

Вы можете сделать что-то вроде этого:

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);
        //...
    }
    
1 голос
/ 14 марта 2014

Я столкнулся с той же проблемой со сценарием содержимого, пытающимся открыть порт на расширении 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 мс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...