Последовательное чтение массива файлов в JS: без рекурсии
Быстрый ответ
Чтобы выполнять промисы последовательно, следует использовать метод .reduce()
инициализированный через Promise.resolve()
. Давайте же приступим к рассмотрению его работы:
let promiseFunctions = [func1, func2, func3]; // Это функции, которые возвращают промисы
promiseFunctions.reduce((chain, promiseFunction) =>
chain.then(promiseFunction), Promise.resolve());
Замените func1
, func2
, func3
на функции, которые вы используете в коде и которые возвращают промисы. Ваша последовательность промисов будет обработана как строго отлаженная очередь!
Внедряем async/await для повышения читаемости кода
Механизм reduce()
является надёжным, однако, в некоторых случаях предпочтительнее использовать async/await
для обеспечения большей чистоты и понятности кода. Вот как это выглядит на практике:
const runSequentially = async (promiseFunctions) => {
let results = []; // Здесь будут собираться результаты
for (let promiseFunction of promiseFunctions) {
results.push(await promiseFunction()); // Выполняем промисы последовательно
}
return results; // Возвращаем результаты
};
Как собрать все результаты выполнения промисов
Если вам необходимо сохранить результаты всех промисов, то можно модифицировать .reduce()
следующим образом:
promiseFunctions.reduce((chain, promiseFunction) => {
return chain.then((resultArray) =>
promiseFunction().then(result => resultArray.concat(result)) // Добавляем результат в массив
);
}, Promise.resolve([]));
Теперь у вас есть массив с результатами выполнения промисов в исходном порядке.
Специализированные промисы с помощью библиотеки Bluebird
Сторонние библиотеки, такие как Bluebird, предлагают функции вида Promise.each()
, обеспечивающие надлежащую последовательность выполнения промисов:
Promise.each(promiseFunctions, function(promiseFunction) {
return promiseFunction(); // Промисы выполняются по последовательности
});
Оцените, насколько внедрение сторонних библиотек будет обоснованно в вашем проекте, прежде чем начинать их использование.
Визуализация
Промисы можно визуализировать как пассажиров поезда 🚂:
Поезд Промисов:
🚂 == 📦➡️📦➡️📦
Каждый "пассажир" (промис) в последовательности должен выполниться перед тем, как наступит очередь следующего:
Последовательность:
1. 🚂==📦🔒➡️📦 ➡️📦
2. 🚂==📦 ➡️📦🔒➡️📦
3. 🚂==📦 ➡️📦 ➡️📦🔒
Поезд останавливается на каждой станции, так же, как и промисы выполняются один за другим.
Лучшие практики и предостережения – ваша забота о безопасности
Имея дело с промисами, не забывайте о следующих рекомендациях:
Избегайте рекурсии, чтобы не попасть в ловушку переполнения стека
Обходите рекурсию стороной, выбрав в пользу .reduce()
или async/await
, что сделает ваш код более прозрачным.
Гарантируйте совместимость
Убедитесь, что окружение, в котором функционирует ваш код, поддерживает современные синтаксические конструкции, например, async/await
.
Следуйте принципам чистого и модульного кода
Целесообразное разделение кода на модули упрощает его понимание и поддержку. Модульный код — как конструктор, состоящий из отдельных блоков.
Используйте современный синтаксис для ясности
Прибегайте к современным возможностям ECMAScript, например стрелочные функции, это облегчит чтение и понимание кода.
Полезные материалы
- Promise – JavaScript | MDN — всё об использовании промисов в документации MDN.
- Using promises – JavaScript | MDN — данные о цепочках промисов.
- Promises chaining — информация о последовательном выполнении промисов.
- Stack Overflow — сообщество программистов, объясняющее работу с последовательностью промисов.
- Understanding Promises | DigitalOcean — статья о принципах работы с промисами.
- Understanding async await | PonyFoo — статья, объясняющая
async & await
. - Medium — обсуждение последовательного выполнения JavaScript.