Comments 26
return result куда потеряли?
Сложность с async/await у меня одна: он вирусный. Всё начинается с одной функции, но очень скоро оно вынуждает преобразовать буквально каждую функцию приложения в async, и пихать await перед каждым запросом данных. Решения этой проблемы глобально я не знаю. Можно, конечно, городить разворачивание промисов, если те передаются в качестве аргументов другим функциям, но SRP при этом сразу идёт лесом, т.к. туда же придётся перевезти часть управляющих конструкций, зависящих от результата асинхронной операции.
Обычно превращается во что-то такое (пример из головы, не обязан компилиться)
const inv: Inventory = await Inventories.create({ id: 'efrvukij' }, { persistent: false });
const bread = await inv.items.create({ name: 'bread', amount: 4});
const foundWater = await inv.items.findOne({ name: 'water' });
const len = await inv.items.count();
if (len > 3 && foundWater) {
if (await foundWater.delete()) {
UI.Notify(`It's done!`)
}
}
Ехал await через await. И это только логика, без обработки исключений при работе с БД, например, которые могут случиться хоть в каждой из функций враппера выше.
Не вижу ничего плохого в приведенном примере, с колбеками или прямая работа с промисами выглядела бы куда хуже
Ну так это плата за корутины без стека.
Либо у нас stackless и растём снизу вверх либо мы сверху вниз сохраняя стек (stackful).
Производительнее для модели JS стек не сохранять.
Можно параллельно и без гибридного подхода...
a = getPromise();
b = getPromise();
await a;
await b;
Тимофей Тиунов: “В данном примере async не нужен. Вот пример, где как бы есть await, но в конце возвращается promise:
Полагаю, что в примере, к которому написано это замечание, могут быть асинхронные вопросы, результат которых возвращается, например, что-то вроде этого (пример условный):
async function loadData(id) {
let response;
try {
response = await fetch(`/data/${id}`);
} catch (e) {
console.error('request failed by the reason:', e);
return null;
}
return response;
}
Эта функция возвращает Promise, хотя сам по себе объект response
таковым и не является.
Честно говоря, не понятно, зачем было тогда переводить статью, если у вас к ней столько замечаний? Может, лучше было написать свою с правильными примерами, а оригинал указать в качестве источника вдохновения, а то выглядит как попытка касаться умнее какого-то автора в интернете.
Согласен. Практика показывает, что если функция возвращает Promise, она всегда должна быть помечена как async. Это и нагляднее, и убережет от случая когда функция будет изменена и вместо Promise будет возвращено обычное значение, к чему клиентский код может быть не готов.
… или просто возьмите Typescript.
одно другому не мешает
Здравый смысл мешает. Нет нужды городить лишнюю абстрацию поверх вызова promise, если проблемы с "клиентский код может быть не готов" не существует как класс.
async перед именем функции - на лишнюю абстракцию не тянет. Было бы интересно услышать доводы против этого (как для JS так и в TS).
async
перед именем функции это не чёрная магия. Это runtime
. По сути:
function a() {
return new Promise((resolve, reject) => {
Promise.resolve(1).then(resolve, reject);
});
}
async function b() {
return await Promise.resolve(1); // либо без await
}
Это плюс минус одно и то же. async
тут просто сахар. А можно просто так:
function c() {
return Promise.resolve(1);
}
С практической точки зрения разница (a
и c
):
- могут быть отличия в stack traces
- немного лишнего runtime т.к. создаётся лишний сегмент promise-матрёшки со всеми вытекающими. Promise сам по себе тяжёлая абстракция, а async-await втройне (там ведь finite machine)
- в non-async функции случайно не напишешь await
- некоторые тонкости в обработке ошибок (это камень в сторону варианта
c
) - в случае какой-нибудь утиной типизации нельзя вернуть не
Promise
(хотя ну её эту утиную типизацию, если честно) - полагаю на уровне lib-uv можно поймать приколы вроде разной обработки очереди (но тут надо вникать, мне лень)
Я конечно душнила ещё тот. Но статьи пережевывающие одну и ту же тему уже просто в глазах мельтешат. Реферат за рефератом, это похоже на то что люди просто себе делают заметку в процессе обучения, в виде статьи на хабре. Оригинальные темы, исследования, гипотезы уже исчерпали себя. Только хардкорная перепечатка давно известных тем. Копни Хабр поглубже найдётся статей 5 про as/aw. Копни медиум, индусы насыпят ещё 50. Мне что-то это напомнило систему в университете, когда у научного сотрудника оклад может зависить от цитируемости. Теперь это ушло в hh плоскость, потенциальные сотрудники стараются увеличить объём публикаций в надежде на строчечку в резюме: публикации - хабр.
Представим, что нам нужно выполнить операцию с большим набором данных для книжного магазина. Наша задача — найти всех авторов, написавших более 10 книг, в нашем наборе данных и вернуть их биографические данные.
это один запрос с join, count в базу. Не стоит разбивать на задачи и обрабатывать на беке
Абсолютно верно, тот самый случай, когда важно поставить правильную задачу, а не вот это вот "10 запросов на бекенд", хотя случаи всякие бывают, конечно. Думаю, именно из-за подобных проблем и родился GraphQL.
.. представим, что данные об авторах и книгах берутся из публичного источника на чужом сервере..
..представим, что надо найти всех авторов, проживающих не более чем в 10 часах езды на автомобиле от указанной точки. Расчёт выполняется через Яндекс.Карты...
Не для всех задач все данные удобно лежат на собственном сервере.
С async/await
асинхронный код выглядит, как обычный синхронный код. Это позволяет записать больше логики в одном методе, но также кроет в себе опасность, особенно для начинающих разработчиков. Из-за этого они плохо понимают, как работает асинхронность, и просто ставят async/await
везде, где только можно.
На самом деле, код после await
, выполняется в другой момент времени и должен выносится в отдельный метод, подобно обработчикам событий. Это избавляет от хеллов и лучше с точки зрения разделения кода.
У меня есть видео-урок по асинхронности, там более подробно об этом рассказано: https://youtu.be/p0d8p9C2aYs
async и await — это синтаксический сахар поверх Promise, который позволяет писать асинхронный код так, как будто инструкции выполняются сверху вниз одна за другой, местами значительно упрощает структуру кода и повышает читаемость.
async и await не является синтаксическим сахаром к Promise. Это синтаксический сахар к генератору, который каждый yield оборачивает в Promise.
Иначе говоря код с async awaite точно так же переписывается используя генераторы, без использования sync и await.
Сравниваем async/await и then/catch с примерами