Меняем Async/Await на Promises.allSettled() для ускорения API-вызовов в Node.JS



Книга Меняем Async/Await на Promises.allSettled() для ускорения API-вызовов в Node.JS

Задача


Функционал массового редактирования позволяет выбрать несколько записей и редактировать все одновременно.


Но изменение более чем 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:


async/await и promise

С 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 сек.



364   0  

Comments

    Ничего не найдено.