Ответ 1
Обновление (2017)
Здесь, в 2017 году, Promises встроены в JavaScript, они были добавлены спецификацией ES2015 (полисы доступны для устаревших сред, таких как IE8-IE11). Синтаксис, который они использовали, использует обратный вызов, который вы передаете в конструктор Promise
(исполнитель Promise
), который получает функции для разрешения/отклонения обещания в качестве аргументов.
Во-первых, поскольку async
теперь имеет смысл в JavaScript (хотя это только ключевое слово в определенных контекстах), я будет использовать later
как имя функции, чтобы избежать путаницы.
Базовая задержка
Используя native Promises (или верный polyfill), он будет выглядеть так:
function later(delay) {
return new Promise(function(resolve) {
setTimeout(resolve, delay);
});
}
Обратите внимание, что это предполагает версию setTimeout
, которая соответствует определению для браузеров, где setTimeout
не передает никаких аргументов к обратному вызову, если вы не дадите им после интервала (это может быть неверно в нерабочих средах и не было правдой в Firefox, но теперь это верно в Chrome и даже в IE8).
Базовая задержка со значением
Если вы хотите, чтобы ваша функция дополнительно передавала значение разрешения, на любом неопределенно современном браузере, который позволяет вам давать дополнительные аргументы setTimeout
после задержки, а затем передает их на обратный вызов при вызове, вы можете сделать это ( текущий Firefox и Chrome; IE11 +, предположительно Edge; не IE8 или IE9, не знаю об IE10):
function later(delay, value) {
return new Promise(function(resolve) {
setTimeout(resolve, delay, value); // Note the order, `delay` before `value`
/* Or for outdated browsers that don't support doing that:
setTimeout(function() {
resolve(value);
}, delay);
Or alternately:
setTimeout(resolve.bind(null, value), delay);
*/
});
}
Если вы используете функции стрелок ES2015 +, это может быть более кратким:
function later(delay, value) {
return new Promise(resolve => setTimeout(resolve, delay, value));
}
или даже
const later = (delay, value) =>
new Promise(resolve => setTimeout(resolve, delay, value));
Отмена задержки со значением
Если вы хотите отменить тайм-аут, вы не можете просто вернуть обещание от later
, потому что Promises не может быть отменено.
Но мы можем легко вернуть объект с помощью метода cancel
и аксессуар для обещания и отклонить обещание об отмене:
const later = (delay, value) => {
let timer = 0;
let reject = null;
const promise = new Promise((resolve, _reject) => {
reject = _reject;
timer = setTimeout(resolve, delay, value);
});
return {
get promise() { return promise; },
cancel() {
if (timer) {
clearTimeout(timer);
timer = 0;
reject();
reject = null;
}
}
};
};
Живой пример:
const later = (delay, value) => {
let timer = 0;
let reject = null;
const promise = new Promise((resolve, _reject) => {
reject = _reject;
timer = setTimeout(resolve, delay, value);
});
return {
get promise() { return promise; },
cancel() {
if (timer) {
clearTimeout(timer);
timer = 0;
reject();
reject = null;
}
}
};
};
const l1 = later(100, "l1");
l1.promise
.then(msg => { console.log(msg); })
.catch(() => { console.log("l1 cancelled"); });
const l2 = later(200, "l2");
l2.promise
.then(msg => { console.log(msg); })
.catch(() => { console.log("l2 cancelled"); });
setTimeout(() => {
l2.cancel();
}, 150);