Существует три основных способа решения этой задачи с помощью Обещаний.
.reduce()
шаблон.
function waitFor(timeout) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(`Finished waiting ${timeout} milliseconds`);
}, timeout);
});
}
var timeouts = [1000, 2000, 2000, 3000, 1000],
sequence = tos => tos.reduce((p,c) => p.then(rp => waitFor(c))
.then(rc => console.log(`${rc} @ ${new Date().getSeconds()}`)), Promise.resolve());
sequence(timeouts);
- Рекурсивный шаблон.
function waitFor(timeout) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(`Finished waiting ${timeout} milliseconds`);
}, timeout);
});
}
var timeouts = [1000, 2000, 2000, 3000, 1000],
sequence = ([to,...tos]) => to !== void 0 && waitFor(to).then(v => (console.log(`${v} @ ${new Date().getSeconds()}`), sequence(tos)));
sequence(timeouts);
- Сканирование по левому шаблону.
Шаблон scanl
будет последовательно выполнять обещания один за другим, но после его выполнения у вас также будет доступ к временным разрешениям обещаний. Это может быть полезно в некоторых случаях. Если вы собираетесь строить асинхронную древовидную структуру лениво (ветвление от узлов только при необходимости), вам нужно иметь доступ к предыдущим разрешениям обещаний.
Чтобы достичь функциональности scanl
в JS, сначала мы должны реализовать ее.
var scanl = (xs, f, acc) => xs.map((a => e => a = f(a,e))(acc))
мы передаем scanl
с помощью xs
, который является массивом тайм-аутов в этом конкретном примере, f
, который является функцией обратного вызова, которая принимает acc
(аккумулятор) и e
(текущий элемент) и возвращает новый аккумулятор. Значения накопителя (временные разрешения) отображаются в массиве тайм-аутов, к которому необходимо обращаться при необходимости.
function waitFor(timeout) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(`finished waiting ${timeout} milliseconds`);
}, timeout);
});
}
var timeouts = [1000, 2000, 2000, 3000, 1000],
scanl = (xs, f, acc) => xs.map((a => e => a = f(a,e))(acc)),
proms = scanl(timeouts, // input array
(a,t,r) => a.then(v => (r = v, waitFor(t))) // callback function
.then(v => (console.log(`${r} and ${v}`),
`${r} and ${v}`)),
Promise.resolve(`Started with 0`)); // accumulator initial value
// Accessing the previous sub sequential resolutions
Promise.all(proms)
.then(vs => vs.forEach(v => console.log(v)));
.as-console-wrapper {
max-height: 100% !important
}