Внедрение тайм-аутов для обратных вызовов node.js
Это типичная ситуация в node.js:
asyncFunction(arguments, callback);
Когда asynFunction
завершается, вызывает вызов callback
. Проблема, которую я вижу в этом шаблоне, заключается в том, что если asyncFunction
никогда не завершается (а asynFunction
не имеет встроенной системы тайм-аута), то callback
никогда не будет вызываться. Хуже того, кажется, что callback
не имеет способа определить, что asynFunction
никогда не вернется.
Я хочу реализовать "тайм-аут", когда if callback
не был вызван asyncFunction
в течение 1 секунды, тогда callback
автоматически вызывается с предположением, что asynFunction
имеет ошибку. Каков стандартный способ сделать это?
Ответы
Ответ 1
Я не знаком с библиотеками, которые это делают, но не сложно подключить себя.
// 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();
}
});
Ответ 2
Вам, вероятно, нужно выйти с помощью собственного решения. Как
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));
Ответ 3
Вы можете сделать что-то вроде этого:
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);
//...
}
Ответ 4
Я столкнулся с той же проблемой, когда содержимое script пыталось открыть порт на BG-расширении до того, как расширение BG было готово. Работать было ждать, пока расширение BG ответит на сообщение и повторит это до успешного завершения. Вот фрагменты кода.
Содержимое 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
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 мс.