Есть ли версия setTimeout, которая возвращает обещание ES6?
Как и этот вопрос, но вместо того, чтобы спрашивать о том, как promises работает вообще, я специально хочу знать:
Каков стандартный/лучший способ обернуть setTimeout в то, что возвращает Promise? Я думаю что-то вроде Angular $timeout
function, но не Angular.
Ответы
Ответ 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!')
не будет вызываться.