Задача
Функционал массового редактирования позволяет выбрать несколько записей и редактировать все одновременно.
Но изменение более чем 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