Я слышу, что люди «не очень понимают обещания», по крайней мере, несколько раз в месяц, и каждый раз я думаю, что я не один из этих людей.

Здесь я опишу случай, с которым недавно столкнулась моя команда, и то, как он был разрешен. Просто скажу, что я не большой поклонник обратных вызовов и «старого способа» реализации обещаний, но мне нравится способ async / await.

Там будет описание шагов, которые мы прошли, поэтому, если вам нужно окончательное решение - пролистайте до конца статьи.

Описание проблемы

Итак, сначала позвольте мне описать проблему. У нас был массив значений, который нам нужно было перебрать и передать каждый элемент массива функции в качестве одного из аргументов (функция возвращает Promise). Второй аргумент - это соединение с базой данных. В конце нам нужно было передать массив значений (не обещаний) другой функции. Кроме того, функция возвращала объект со значением, которое должно было использоваться внутри того же цикла. Основная цель заключалась в достижении наилучших результатов производительности и хорошей читаемости кода.

Первоначальная версия

Первая версия кода:

В приведенном выше случае был красивый синтаксис async / await, в то время как мы сделали вид, что использовали Promises. asyncForEach () ожидает обратного вызова, немедленно разрешает его, и разрешенное значение помещается в finalArray. В этом случае значение из asyncFunction () разрешается немедленно, поэтому нам не нужны обещания. Здесь у нас просто красивый и распространенный синтаксис async / await :). Чтобы повысить производительность, нам нужно было поместить все Promise в массив, а затем разрешить все сразу, как показано здесь.

Но в этом случае наш код будет выглядеть примерно так:

Такой подход немного улучшит производительность. Однако читаемость будет хуже, и появится дополнительный код (еще один цикл). Кроме того, мы по-прежнему не достигли максимальной производительности (итерация по разрешенным значениям потребовала бы дополнительного времени / ресурсов). Поэтому было решено не реализовывать его и попытаться найти более «перспективный» путь.

Пришло время обратного звонка?

Лучше дать инструкции Promise о действиях, которые необходимо выполнить после того, как оно будет разрешено. А вот и then (). Мы можем отправить вызов функции в массив, не разрешая его, и включить в обратный вызов инструкции для действий со значениями. Это означает, что как только Promise будет разрешен (после цикла forEach ()), нам действительно не нужно беспокоиться о другом цикле для итерации по каждому из значений, потому что он уже присутствует во время разрешения. Итак, вот код:

Обратный вызов получает Promise, и как только он достигает Promise.all (), обратный вызов разрешается. Никакого дополнительного цикла, никакой траты времени, никакого дополнительного кода. Производительность в этом случае была значительно лучше, чем в исходной.

Не беспокойтесь, если это по-прежнему не работает: возможно, вы все еще используете соединение MySQL с Promises. Вместо этого используйте Pool. Соединение открывается на каждой итерации цикла, что не является «здоровым», учитывая тот факт, что asyncFunction () работает параллельно (почти) с каждым из элементов myArray. . Использование createPool () будет иметь много подключений к базе данных одновременно и будет повторно использовать подключения, которые завершили предыдущий запуск. Pool - идеальное решение для асинхронных операций (если вы не задумываетесь об ограничениях и / или пытаетесь отключить соединение приложения с базой данных MySQL). Но then () - это «старый способ», поэтому его недостаточно.

Окончательное решение (я)

Итак, как мы можем избавиться от обратного вызова, улучшить читаемость и сохранить ту же производительность? Вот окончательное решение:

Or:

Если вам нравится добавлять новые пакеты npm, посмотрите bluebird, у него есть Promise.map (), который может делать и то, и другое - Promise.all () и map ().

Заключение

Окончательное решение имеет лучшую производительность, читаемость кода была достаточно хорошей и без лишнего кода. Этот случай помог мне немного лучше понять Promises, но все же я не уверен, что я один из тех, кто «действительно понимает обещания».