Вы всё-таки не поняли что я имел ввиду, позвольте уточнить. По другому первый пример можно представить вот так:
Другая версия первого примера
function doFinalThingCallback(err) {
if (err) { handleAnotherError(err); }
// Выполнено
} // конец doFinalThing
function doMoreStuffCallback(responseThree, err) {
if (err) { handleAnotherError(err); }
doFinalThing(responseThree, doFinalThingCallback);
} // конец doMoreStuff
function doSomethingElseCallback(responseTwo, err) {
if (err) { handleError(err); }
doMoreStuff(responseTwo, doMoreStuffCallback);
} // конец doSomethingElse
function doSomethingCallback(responseOne) {
doSomethingElse(responseOne, doSomethingElseCallback);
} // конец doSomething
doSomething(doSomethingCallback); // конец doSomething
Теперь функции НЕ анонимные. Но последовательность выполнения по прежнему не очевидна. Я бы сформулировал эту проблему так:
ты либо видишь кодовую ёлку(пример с коллбеками из предыдущего поста), в которой тяжело что-либо понять, но весь процесс в одном месте,
либо код красивый(текущий пример), но что бы увидеть последовательность нужно по всем этим функциям пробежаться.
Функции могут быть анонимными или именными, сути дела это не меняет — в одном месте кода находится полная последовательность выполнения. Представьте то время, которое вы НЕ потратите с промисами, разбирая чужой код...
Продвинутая ошибка №3 — промисы против фабрик промисов
Допустим, вы хотите выполнить серию промисов один за другим, последовательно. Вы хотите что-то вроде Promise.all(), но такой, чтобы не выполнял промисы параллельно.
Сгоряча вы можете написать что-то подобное:
function executeSequentially(promises) {
var result = Promise.resolve();
promises.forEach(function (promise) {
result = result.then(promise);
});
return result;
}
К сожалению, пример выше не будет работать так, как задумывалось. Промисы из списка, переданного в executeSequentially(), все равно начнут выполняться параллельно.
Причина в том, что по спецификации промис начинает выполнять заложенную в него логику сразу после создания. Он не будет ждать. Таким образом, не сами промисы, а массив фабрик промисов — это то, что действительно нужно передать в executeSequentially:
function executeSequentially(promiseFactories) {
var result = Promise.resolve();
promiseFactories.forEach(function (promiseFactory) {
result = result.then(promiseFactory);
});
return result;
}
Я знаю, вы сейчас думаете: «Кто, черт возьми, этот Java программист, и почему он рассказывает нам о фабриках?». На самом деле фабрика — это простая функция, возвращающая промис:
function myPromiseFactory() {
return somethingThatCreatesAPromise();
}
Почему этот пример будет работать? А потому, что наша фабрика не создаст промис до тех пор, пока до него не дойдет очередь. Она работает именно как resolveHandler для then().
Посмотрите внимательно на функцию executeSequentially() и мысленно замените ссылку на promiseFactory ее содержимым — сейчас над вашей головой должна радостно вспыхнуть лампочка :)
Не согласен, промисы при любом раскладе сильно лучше колбеков. Дождитесь перевода второй статьи Promises 102, где подробно рассказано о том, как их готовить. Так же рекомендую вам ознакомиться со статьёй У нас проблемы с промисами. Автор рассматривает всевозможные проблемы, которые могут возникнуть и возникают при неправильном использовании промисов.
По поводу вашего вопроса, я уже ссылался выше на статью Async/Await в javascript. Взгляд со стороны
Конкретно на ваш вопрос отвечает следующая цитата:
А если мне нужно одновременно получить результат от нескольких вызовов?
Так как мы уже разобрались, что мы имеем дело с Promise. Следовательно можно использовать метод .all() объекта Promise для решения такого рода задач.
async function unicorn() {
let [rainbow, food] = await Promise.all([getRainbow(), getFood()]);
return {rainbow, food}
}
Который вы выберете?
Единственную ассоциацию, которую вызывает у меня первый пример кода это: "Хочется взять, и переписать!", в то время, как во втором я фрагменте я отчетливо вижу что после чего происходит.
Говоря общедоступным языком async/await — это Promise.
Когда вы объявляете функцию как асинхронную, через волшебное слово async, вы говорите, что данная функция возвращает Promise. Каждая вещь которую вы ожидаете внутри этой функции, используя волшебное слово await, то же возвращает Promise.
Из этого можно сделать вывод о том, что async/await являются в большей степени синтаксическим сахаром для промисов. Функция синхронной не становится, поток при этом не блокируется.
И да и нет. В простейших ситуациях промисы действительно больше похожи на удобную обёртку. Однако уже .then() и .catch() дают нам мощный инструмент для управления последовательностью выполнения. А кроме этого есть еще Promise.all() и Promise.race(). Эти методы подробно рассматриваются во второй статье Promises 102(ссылка на оригинал, статья будет переведена в течение ближайшей недели).
Вы всё-таки не поняли что я имел ввиду, позвольте уточнить. По другому первый пример можно представить вот так:
Теперь функции НЕ анонимные. Но последовательность выполнения по прежнему не очевидна. Я бы сформулировал эту проблему так:
С промисами ситуация абсолютно обратная
Функции могут быть анонимными или именными, сути дела это не меняет — в одном месте кода находится полная последовательность выполнения. Представьте то время, которое вы НЕ потратите с промисами, разбирая чужой код...
Ответ на ваш вопрос можно найти в статье У нас проблемы с промисами или вот под спойлером:
Допустим, вы хотите выполнить серию промисов один за другим, последовательно. Вы хотите что-то вроде
Promise.all()
, но такой, чтобы не выполнял промисы параллельно.Сгоряча вы можете написать что-то подобное:
К сожалению, пример выше не будет работать так, как задумывалось. Промисы из списка, переданного в
executeSequentially()
, все равно начнут выполняться параллельно.Причина в том, что по спецификации промис начинает выполнять заложенную в него логику сразу после создания. Он не будет ждать. Таким образом, не сами промисы, а массив фабрик промисов — это то, что действительно нужно передать в
executeSequentially
:Я знаю, вы сейчас думаете: «Кто, черт возьми, этот Java программист, и почему он рассказывает нам о фабриках?». На самом деле фабрика — это простая функция, возвращающая промис:
Почему этот пример будет работать? А потому, что наша фабрика не создаст промис до тех пор, пока до него не дойдет очередь. Она работает именно как
resolveHandler
дляthen()
.Посмотрите внимательно на функцию
executeSequentially()
и мысленно замените ссылку наpromiseFactory
ее содержимым — сейчас над вашей головой должна радостно вспыхнуть лампочка :)Не согласен, промисы при любом раскладе сильно лучше колбеков. Дождитесь перевода второй статьи Promises 102, где подробно рассказано о том, как их готовить. Так же рекомендую вам ознакомиться со статьёй У нас проблемы с промисами. Автор рассматривает всевозможные проблемы, которые могут возникнуть и возникают при неправильном использовании промисов.
По поводу вашего вопроса, я уже ссылался выше на статью Async/Await в javascript. Взгляд со стороны
Конкретно на ваш вопрос отвечает следующая цитата:
Так как мы уже разобрались, что мы имеем дело с
Promise
. Следовательно можно использовать метод.all()
объекта Promise для решения такого рода задач.Тут я с вами не соглашусь. Допустим, вам предлагают на выбор один из двух проектов:
Который вы выберете?
Единственную ассоциацию, которую вызывает у меня первый пример кода это: "Хочется взять, и переписать!", в то время, как во втором я фрагменте я отчетливо вижу что после чего происходит.
Позвольте процитировать другую статью на хабре — Async/Await в javascript. Взгляд со стороны:
Говоря общедоступным языком async/await — это Promise.
Когда вы объявляете функцию как асинхронную, через волшебное слово async, вы говорите, что данная функция возвращает Promise. Каждая вещь которую вы ожидаете внутри этой функции, используя волшебное слово await, то же возвращает Promise.
Из этого можно сделать вывод о том, что async/await являются в большей степени синтаксическим сахаром для промисов. Функция синхронной не становится, поток при этом не блокируется.
.then()
и.catch()
дают нам мощный инструмент для управления последовательностью выполнения. А кроме этого есть ещеPromise.all()
иPromise.race()
. Эти методы подробно рассматриваются во второй статье Promises 102(ссылка на оригинал, статья будет переведена в течение ближайшей недели).