Как реализовать "тайм-аут функции" в Javascript - не только "setTimeout",
Как реализовать timeout в Javascript, а не window.timeout
, но что-то вроде session timeout
или socket timeout
- в основном - "function timeout
"
Указанный период времени, который будет разрешен в системе до того, как должно произойти указанное событие, если иное не указано событие происходит первым; в любом случае период прекращается, когда происходит либо событие.
В частности, я хочу javascript observing timer
, который будет наблюдать за временем выполнения функции, и если он достигнет или пройдет больше определенного времени, тогда observing timer
остановит/уведомит исполняющую функцию.
Любая помощь очень ценится! Большое спасибо.
Ответы
Ответ 1
Я не совсем понимаю, что вы спрашиваете, но я думаю, что Javascript не работает так, как вы хотите, поэтому это невозможно. Например, не может быть сделано, что регулярный вызов функции длится либо до завершения операции, либо определенного количества времени в зависимости от того, что наступит раньше. Это может быть реализовано вне javascript и открыто через javascript (как это делается с синхронными вызовами ajax), но не может быть сделано в чистом javascript с регулярными функциями.
В отличие от других языков, Javascript является однопоточным, так что во время выполнения функции таймер никогда не будет выполняться (за исключением веб-работников, но они очень и очень ограничены в том, что они могут делать). Таймер может выполняться только тогда, когда функция завершает выполнение. Таким образом, вы не можете передавать переменную прогресса между синхронной функцией и таймером, поэтому нет возможности таймерам "проверять" ход выполнения функции.
Если ваш код был полностью автономным (не имел доступа к какой-либо из ваших глобальных переменных, не вызывал ваши другие функции и вообще не имел доступа к DOM), вы можете запустить его в веб-рабочем (доступно только в новых браузерах) и используйте таймер в основном потоке. Когда код веб-рабочего пользователя завершается, он отправляет сообщение в основной поток с результатами. Когда основной поток получает это сообщение, он останавливает таймер. Если таймер срабатывает перед получением результатов, он может убить веб-исполнителя. Но ваш код должен был бы жить с ограничениями веб-работников.
Soemthing можно также выполнить с асинхронными операциями (потому что они работают лучше с однопоточным Javascript), например:
- Запустите асинхронную операцию, например, вызов ajax или загрузку изображения.
- Запустите таймер, используя
setTimeout()
для вашего времени ожидания.
- Если таймер срабатывает до завершения асинхронной операции, остановите асинхронную операцию (используя API для ее отмены).
- Если асинхронная операция завершается до запуска таймера, отмените таймер на
clearTimeout()
и продолжите.
Например, здесь, как поместить таймаут на загрузку изображения:
function loadImage(url, maxTime, data, fnSuccess, fnFail) {
var img = new Image();
var timer = setTimeout(function() {
timer = null;
fnFail(data, url);
}, maxTime);
img.onLoad = function() {
if (timer) {
clearTimeout(timer);
fnSuccess(data, img);
}
}
img.onAbort = img.onError = function() {
clearTimeout(timer);
fnFail(data, url);
}
img.src = url;
}
Ответ 2
Вы можете выполнить код в веб-работнике. Тогда вы все еще можете обрабатывать события тайм-аута во время работы кода. Как только веб-исполнитель закончит свою работу, вы можете отменить тайм-аут. И как только произойдет тайм-аут, вы можете завершить работу веб-мастера.
execWithTimeout(function() {
if (Math.random() < 0.5) {
for(;;) {}
} else {
return 12;
}
}, 3000, function(err, result) {
if (err) {
console.log('Error: ' + err.message);
} else {
console.log('Result: ' + result);
}
});
function execWithTimeout(code, timeout, callback) {
var worker = new Worker('data:text/javascript;base64,' + btoa('self.postMessage(' + String(code) + '\n());'));
var id = setTimeout(function() {
worker.terminate();
callback(new Error('Timeout'));
}, timeout);
worker.addEventListener('error', function(e) {
clearTimeout(id);
callback(e);
});
worker.addEventListener('message', function(e) {
clearTimeout(id);
callback(null, e.data);
});
}
Ответ 3
Вы можете добиться этого только с помощью некоторых хардкорных трюков. Например, если вы знаете, какую переменную возвращает ваша функция (обратите внимание, что функция EVERY js возвращает что-то, по умолчанию - undefined
), вы можете попробовать что-то вроде этого: define variable
var x = null;
и запустить тест в отдельном "потоке":
function test(){
if (x || x == undefined)
console.log("Cool, my function finished the job!");
else
console.log("Ehh, still far from finishing!");
}
setTimeout(test, 10000);
и, наконец, запустить функцию:
x = myFunction(myArguments);
Это работает, только если вы знаете, что ваша функция либо не возвращает никакого значения (т.е. возвращаемое значение равно undefined
), либо возвращаемое значение всегда "не является ложным", т.е. не преобразуется в оператор false
например 0
, null
и т.д.).
Ответ 4
Поделитесь переменной между observing timer
и executing function
.
Внесите observing timer
с помощью window.setTimeout
или window.setInterval
. Когда выполняется observing timer
, он устанавливает значение выхода для общей переменной.
executing function
постоянно проверяет значение переменной.. и возвращает, если указано значение выхода.