Как реализовать "тайм-аут функции" в 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 постоянно проверяет значение переменной.. и возвращает, если указано значение выхода.