Как написать простой, понятный, легко обслуживаемый код, который запускает последовательно несколько асинхронных функций в javascript/jQuery?
(когда отработает одна, должна запускаться другая)
Следующий пример иллюстриует мой вопрос:
function f1(){ setTimeout( function(){ console.log(1); }, 30); }
function f2(){ setTimeout( function(){ console.log(2); }, 20); }
function f3(){ setTimeout( function(){ console.log(3); }, 10); }
f1(); f2(); f3();
на выходе 3 2 1
как сделать что-бы выдавало 1 2 3 ?
Желательно без коллбеков - т.к. если надо запустить последовательно больше двух функций это уже тяжело читать.
Многое говорит о том что возможно решение с помощью обьекта $.Deferred, но пока не видел разумного варианта.
Подобный вопрос задавался не раз, но я почему-то не нашел ответа который бы меня устроил.
Ответ
Если вы хотите использовать Обещания (Promise), то для начала вам нужно модифицировать ваши функции так, чтобы они возвращали Обещания. Например, первая из ваших функций будет иметь вид:
function f1() {
return new Promise(function(resolve){
setTimeout(function() {
console.log(1);
resolve();
}, 30);
});
}
Остальные функции преобразуются аналогичным образом.
Теперь у вас есть три функции (f1, f2, f3), которые возвращают Обещания и вы хотите выполнить их последовательно. Если вы не используете библиотек, вроде Bluebird, то вам придется реализовать очередь вызова Обещаний вручную. Это не так сложно, как кажется:
// Аргумент "deeds" - это массив функций, которые должны выполняться
// последовательно. При этом, каждая функция должна возвращать
// Обещание (Promise).
var seqRunner = function(deeds) {
return deeds.reduce(function(p, deed) {
return p.then(function() {
// Выполняем следующую функцию только после того, как отработала
// предыдущая.
return deed();
});
}, Promise.resolve()); // Инициализируем очередь выполнения.
}
А пользоваться этой очередью нужно вот так:
seqRunner([f1, f2, f3]).then(function() {
console.log('Done!');
});
А вот и JSFiddle с рабочим примером
Замечание:
Если у вас заранее известное, небольшое число функций, то можно вообще обойтись без функции seqRunner и связывать функции вручную:
f1().then(function() {
return f2();
}).then(function() {
return f3();
}).then(function() {
console.log('Done!');
});
Комментариев нет:
Отправить комментарий