Задача
Функционал массового редактирования позволяет выбрать несколько записей и редактировать все одновременно.
Но изменение более чем 50 записей может занять до 50 секунд, и страница зависает. Ожидание сбивает с толку пользователей, и те часто спешат уйти со страницы. Нужно ускорить такое редактирование.
Откуда это замедление?
Код написан так:
for (r in records) {
await update(r);
}
При изменении одной записи делается API-вызов, на который уходит от 500 мс до 1 сек.
Поскольку записи перебираются и изменяются одна за другой, это время увеличивается линейно — по мере роста их числа.
Промис для ускорения
К счастью, не нужно ждать завершения изменения, прежде чем обработать следующее. Promise.allSettled() позволяет делать запрос его изменения до завершения предыдущего.
Вот что мы сделали:
const allPromises = [];
for (r in records) {
const promise = update(r);
allPromises.push(promise);
};
await Promise.allSettled(allPromises);
Проиллюстрируем то, что происходит при использовании async/await и promises:

С promise не нужно ждать возвращения каждого запроса на изменение, прежде чем делать следующий. Так экономится много времени.
Получение результатов промисов
К сожалению, иногда update(r) завершается неуспешно.
Если какие-то изменения неуспешны, выявить их можно по разрешенному значению в Promise.allSettled(). Здесь выдается массив, каждым объектом которого описывается результат промиса.
Если промис выполнен, получаем {status: “fulfilled”, value: xxx }.
Если отклонен — {status: “rejected”, reason: xxx }.
Например:
const values = await Promise.allSettled([
Promise.resolve(33),
Promise.reject(new Error('an error'))
])
console.log(values)
// [
// {status: "fulfilled", value: 33},
// {status: "rejected", reason: Error: an error}
// ]
В этом случае нужно узнать id записей с успешными и неуспешными изменениями.
Вот что мы сделали:
const allPromises = [];
for (r in records) {
const promise = new Promise((res, rej) => {
update(t)
.then(() => { res(r.id) }); # успешно
.catch(() => { rej(r.id) }); # неуспешно
});
allPromises.push(promise);
};
const outcomes = await Promise.allSettled(allPromises);
const succeeded = outcomes.filter(o => o.status === "fulfilled");
const succeededIds = succeeded.map(s => s.value);
const failed = outcomes.filter(o => o.status === "rejected");
const failedIds = failed.map(f => f.reason);
Проиллюстрируем то, что происходит, когда промисы неуспешны:

В возвращаемом массиве указано, какие успешны, а какие нет.
Вот и всё. Благодаря смене Async/Await на Promises.allSettled() удалось ускорить операцию массового редактирования более чем 50 записей с более чем 50 сек до менее 5 сек.
Читайте также:
- 6 проверенных методов повышения безопасности Node.js
- Делаем Node.js быстрым: инструменты, техники и советы для создания эффективных серверов на Node.js
- Создание чат-приложения в режиме реального времени с Vue.js, Socket.IO и Node.js
Читайте нас в Telegram, VK и Дзен
Перевод статьи Wendie Sun: Changing Async/Await to Promises.allSettled() to Speed Up API Calls in Node.JS





