Какая лучшая общая практика для тайм-аута функции в обещании

Продвигайте вызов функции с тайм-аутами

Я видел, что многие ресурсы предоставляют похожие примеры использования Promise.race для выключения вызова функции в течение заданного периода времени. Это очень хороший пример того, как Promise.race можно использовать на практике. Вот пример кода:

function doWithinInterval(func, timeout) {
    var promiseTimeout = new Promise(function (fulfill, reject) {
       // Rejects as soon as the timeout kicks in
       setTimeout(reject, timeout);
    });
    var promiseFunc = new Promise(function (fulfill, reject) {
        var result = func(); // Function that may take long to finish
        // Fulfills when the given function finishes
        fulfill(result);
    });

    return Promise.race([promiseTimeout, promiseFunc]);
}

Простой подход, описанный выше с помощью Promise.race, отклоняет обещание, как только тайм-аут запускается до завершения func. В противном случае проект выполняется после завершения функции func до тайм-аута.

Звучит неплохо и просто.

Однако лучше ли использовать тайм-аут в Promise?

Конечно, описанный выше подход можно использовать, если мы хотим установить тайм-аут на вызов функции с помощью Promises. Операции по-прежнему выглядят неплохо. Однако считается ли это хорошей практикой использования тайм-аута в обещании? Если нет, каков недостаток использования этого?

Я искал альтернативные подходы, но не смог найти собственный способ Promise для этого.

Вместо этого некоторые внешние библиотеки Promise предлагают timeout функциональность следующим образом:

  • Bluebird поставляет .timeout()

  • WinJS поставляет .timeout(), а также

  • Q также поставляется с .timeout().

Однако Promise.timeout() не является частью стандартного API ECMAScript 6 (пожалуйста, поправьте меня, если я ошибаюсь). Есть ли какой-либо рекомендуемый способ обработки тайм-аутов изначально с ES6 Promises?

Ответ 1

Это зависит от того, что вы подразумеваете под таймаутом.

Если вы ожидаете, что функция остановится, то нет.

Если вы просто хотите прекратить его ждать, тогда да (быстро взломать ES6):

var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
var timeout = (p, ms) => Promise.race([p, wait(ms).then(() => {
    throw new Error("Timeout after " + ms + " ms");
})]);

var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
var timeout = (p, ms) => Promise.race([p, wait(ms).then(() => {
  throw new Error("Timeout after " + ms + " ms");
})]);

// Example:

var log = msg => div.innerHTML += "<p>" + msg + "</p>";
var failed = e => log(e.toString() + ", line " + e.lineNumber);

log("Waiting 5 seconds...");
timeout(wait(5000), 2000)
.then(() => log("...Done."))
.catch(failed);
<div id="div"></div>

Ответ 2

Собственный метод Promise.race не очищает таймер обещания тайм-аута после того, как фактическое обещание завершится, поэтому процесс будет ждать, пока не будет завершено обещание тайм-аута. Это означает, что если вы установите тайм-аут на 1 час, и наше обещание будет завершено через 1 мин, тогда процесс будет ждать 59 минут до его выхода.

Используйте этот метод вместо:

export function race({promise, timeout, error}) {
  let timer = null;

  return Promise.race([
    new Promise((resolve, reject) => {
      timer = setTimeout(reject, timeout, error);
      return timer;
    }),
    promise.then((value) => {
      clearTimeout(timer);
      return value;
    })
  ]);
}