Подтвердить что ты не робот

Есть ли версия setTimeout, которая возвращает обещание ES6?

Как и этот вопрос, но вместо того, чтобы спрашивать о том, как promises работает вообще, я специально хочу знать:

Каков стандартный/лучший способ обернуть setTimeout в то, что возвращает Promise? Я думаю что-то вроде Angular $timeout function, но не Angular.

4b9b3361

Ответ 1

В браузерах

Прежде всего нет - для этого нет встроенного. Множество библиотек, которые расширяют ES2015 promises, как хлыст с синими птицами.

Я думаю, что другой ответ связывает выполнение функции и задержку, она также создает таймауты, которые невозможно отменить. Я бы написал это просто как:

function delay(ms){
    var ctr, rej, p = new Promise(function (resolve, reject) {
        ctr = setTimeout(resolve, ms);
        rej = reject;
    });
    p.cancel = function(){ clearTimeout(ctr); rej(Error("Cancelled"))};
    return p; 
}

Затем вы можете сделать:

delay(1000).then(/* ... do whatever */);

Или

 doSomething().then(function(){ return delay(1000); }).then(doSomethingElse);

Если мы хотим только базовые функции в ES2015, это еще проще:

let delay = ms => new Promise(r => setTimeout(r, ms));

В Node

Вы можете использовать util.promisify на setTimeout, чтобы вернуть функцию delay, что означает, что вам больше не нужно использовать конструктор new Promise.

Ответ 2

Вот как я его реализую:

function delay(duration, func) {
  var args = Array.prototype.slice.call(arguments, 2);

  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(func.apply(null, args));
    }, duration);
  });
}

(преднамеренно выбран синтаксис ES5)

Но может быть, есть общая библиотека, которая уже делает это, или лучший способ сделать это.

Ответ 3

Если вам нужна правильная отмена обещанного тайм-аута, похожая на clearTimeout - возврат обещания непосредственно из setTimeout не подходит. Особенно при использовании ES7 async/await в блоке try...finally. Лучше иметь отдельную переменную для манипулирования таймаутом. Я реализовал этот подход как крошечный await-timeout пакет. Он работает следующим образом:

import Timeout from 'await-timeout';

async function foo() {
  const timeout = new Timeout();
  try {
    const fetchPromise = fetch('https://example.com');
    const timerPromise = timeout.set(1000).then(() => console.log('Timeout!'));
    await Promise.race([fetchPromise, timerPromise]);
  } finally {
    timeout.clear();
  }
}

В этом примере тайм-аут определенно будет очищен в случае успеха выборки или любой ошибки и console.log('Timeout!') не будет вызываться.