Страницы

Поиск по вопросам

вторник, 6 ноября 2018 г.

Как последовательно вызвать асинхронную функцию с коллбеками?

Есть массив, для каждого элемента которого следует вызвать асинхронную функцию, возвращающую значение через коллбэк.
Однако, требуется вызвать их последовательно, а именно, следующий вызов надо совершать только тогда, когда завершилась обработка предыдущего.
Вот так получается одновременно:
function doSmth(x, callback) { setTimeout(callback, Math.random() * 100 | 0, null, x); } var data = [1, 2, 3, 4, 5, 6, 7, 8]; for (var x of data) { doSmth(x, function (err, res) { console.log(err || res); }); } .as-console-wrapper.as-console-wrapper { max-height: 100vh }


Ответ

Надо делать вызов внутри коллбека. Для этого придётся переписать цикл на рекурсию (ну или не совсем рекурсию):
function doSmth(x, callback) { setTimeout(callback, Math.random() * 100 | 0, null, x); } var data = [1, 2, 3, 4, 5, 6, 7, 8]; (function go(i) { // <================== рекурсивная функция вместо цикла if (i >= data.length) { return; // <======================== выход, когда массив закончился } doSmth(data[i], function (err, res) { console.log(err || res); go(i + 1); // <===================== рекурсивный вызов из коллбэка }); })(0); .as-console-wrapper.as-console-wrapper { max-height: 100vh }
И остаётся ещё один момент - обычно нам бы надо узнать, когда завершилась обработка. Для этого функция go вместо return может вызвать другой коллбэк из вызывающей функции:
function doSmth(x, callback) { setTimeout(callback, Math.random() * 100 | 0, null, x); } function process(data, callback) { (function go(i) { // <================== рекурсивная функция вместо цикла if (i >= data.length) { return callback(null, null); // <=== return позволяет избежать рекурсивного вызова } doSmth(data[i], function (err, res) { if (err) { return callback(err, null); // <== прекращаем дальнейшую обработку } console.log(res); go(i + 1); // <===================== рекурсивный вызов из коллбэка }); })(0); } var data = [1, 2, 3, 4, 5, 6, 7, 8]; process(data, function (err, res) { console.log(err || "Готово!"); }); .as-console-wrapper.as-console-wrapper { max-height: 100vh }

Комментариев нет:

Отправить комментарий