- PVSM.RU - https://www.pvsm.ru -
Это перевод статьи [1], которую Марико Косака написала в качестве альтернативного введения в промисы JavaScript. Наброски иллюстраций она делала в своём блокноте во время чтения разных статей, посвящённых промисам. Если хотите изучить более подробно, в конце вы найдёте список полезных ссылок.
Недавно Марико участвовала в обсуждении того, как можно с помощью JavaScript сделать фичу, которая давала бы доступ к внешним данным (должна была быть асинхронной). Она сказала: «Ну, давайте используем fetch()
… так что в коде… эээ...», и пока силилась вспомнить fetch API, собеседник сказал: «Будет возвращаться промис». По словам Марико, её
Ей приходилось много раз писать код, основанный на промисах, но для полной картины нужные пазлы в её голове почему-то не соединились. Она поняла, что на самом деле не «въезжает» в суть.
Я даже описать не могу, насколько трудно объяснить это выражение: «Будет возвращаться промис»
Но это, наверное, потому, что я не понимаю, что такое «промис».
— Mariko Kosaka (@kosamari) 13 января, 2017 [3]
Если вы полистаете её твиттер [4], то увидите, что при обучении она использует визуальные образы, и для этого рисует используемые в коде концепции в виде физических метафор. Так она пытается справиться с двойным уровнем абстракции (язык программирования и английский в качестве второго языка). Поэтому ей пришлось и в этот раз обратиться к рисованию.
Вот фрагмент кода, который будет использоваться для примера.
// асинхронная операция
function cookBurger (type) { ... }
// обычная операция
function makeMilkshake (type) { ... }
// функция заказа, которая возвращает промис
function order (type) {
return new Promise(function(resolve, reject) {
var burger = cookBurger(type)
burger.ready = function (err, burger) {
if (err) {
return reject(Error('Error while cooking'))
}
return resolve(burger)
}
})
}
order('JakeBurger')
.then( burger => {
const milkshake = makeMilkshake('vanila')
return { burger: burger, shake: milkshake }
})
.then( foodItems => {
console.log('BURGER PARTY !', foodItems)
})
.catch( err => {
console.log(err)
})
Добро пожаловать в Promise Square Park, где находится бургерная JakeShack. Её бургеры очень популярны, но количество кассовых аппаратов для оформления заказов ограничено, так что очередь из клиентов у прилавка всегда большая. Однако, на кухне работают отличные повара, способные одновременно готовить несколько заказов.
Если что, то прототипами стали Madison Square Park и ShakeShack в Нью-Йорке. Там очень вкусно кормят, и очередь всегда большая.
Чтобы как можно быстрее принимать заказы, JakeShack использует систему сигнализаторов. Когда покупатель оплачивает заказ, кассир выдаёт поднос и устройство-сигнализатор в обмен на платеж.
Поднос — это промис JakeShack клиенту, что на подносе окажется вкусный бургер, как только он будет готов, а сигнализатор показывает состояние заказа. Если он молчит, то заказ обрабатывается (pending) — повара на кухне заняты работой над вашим заказом. Когда экран засветится красным и включится звуковой сигнал, это будет означать, что заказ собран (settled).
Небольшой нюанс, связанный с состоянием «собран». Это не синоним «готов». Это означает, что заказ был обработан на кухне и покупателю нужно принять решение о том, что с ним делать дальше. Вы (покупатель), вероятно, захотите забрать заказ за прилавком, однако также возможно, что просто уйдете. Решение за вами.
Давайте взглянем на код. Когда вы вызываете функцию order
, она «возвращает промис» (даёт вам поднос с сигнализатором). Возвращаемое значение (бургер) должно появиться на подносе, когда будет выполнен промис и вызвана callback-функция.
Похоже, сигнализатор зазвонил, а значит, нужно подойти к прилавку и попросить свой заказ. Далее возможны два варианта развития событий.
Вот как можно приготовиться к обеим ситуациям.
.then()
принимает другую функцию в качестве второго аргумента, которая также может использоваться как обработчик reject'а. Для простоты здесь я использовала только .catch()
. Если вам хочется больше узнать о том, как обрабатываются оба варианта, почитайте эту статью: https://developers.google.com/web/fundamentals/getting-started/primers/promises#error_handling [5].
Допустим, ваш заказ был готов, но вы решили, что для бургер-вечеринки вам ещё нужен молочный коктейль. Итак, вы встали в С-очередь (отдельная очередь за напитками, действительно используется в ShakeShack для более эффективного менеджмента заказов). Когда вы заказываете свой коктейль, кассир даёт вам другой поднос и другой сигнализатор. А поскольку молочный коктейль готовится очень быстро, кассир сразу же его и выдаёт, вместе с подносом. Не нужно ждать, когда зазвенит сигнализатор (он уже это делает!).
Теперь посмотрим, как работает наш код. Цепочка промисов — это просто добавление в код нового .then()
. Значение, возвращаемое .then()
, всегда является промисом. Просто запомните, что каждый .then()
возвращает вам поднос и сигнализатор, а настоящее возвращаемое значение передаётся в виде аргумента в callback-функцию.
Теперь у вас есть бургер и молочный коктейль, вы готовы к БУРГЕР-ВЕЧЕРИНКЕ!
У промисов есть ещё парочка методов, позволяющих выполнять клёвые трюки.
Promise.all()
создаёт промис, который принимает в качестве аргумента массив промисов (элементов). Этот промис выполняется тогда, когда выполнены всего его элементы. Допустим, вы заказали 5 разных бургеров для своих друзей, но не хотите ходить и забирать их по одному все 5 раз, а тогда, когда они все будут готовы. В данном случае хорошее решение — Promise.all()
.
Promise.race()
похож на Promise.all()
, но при этом промис считается выполненным или отклонённым, как только будет выполнен или отклонён хотя бы один его элемент. Такое поведение позволяет эмулировать схему «пробуй и хватай» (try and grab). Если вы невероятно голодны, то можете одновременно заказать бургер, чизбургер и хот-дог, но взять то, что первое поступит с кухни. Но в таком случае, если, к примеру, кухня закрылась или перестала почему-то работать, и первым делом отклоняет промис бургера, то и весь промис будет отклонен.
Также можете ещё почитать про промисы:
Автор: NIX Solutions
Источник [8]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/247247
Ссылки в тексте:
[1] статьи: http://kosamari.com/notes/the-promise-of-a-burger-party
[2] мозг: http://www.braintools.ru
[3] 13 января, 2017: https://twitter.com/kosamari/status/819972802220589056
[4] твиттер: https://twitter.com/kosamari
[5] https://developers.google.com/web/fundamentals/getting-started/primers/promises#error_handling: https://developers.google.com/web/fundamentals/getting-started/primers/promises#error_handling
[6] promise-cookbook: https://github.com/mattdesl/promise-cookbook/blob/master/README.md
[7] JavaScript Promises: an Introduction: https://developers.google.com/web/fundamentals/getting-started/primers/promises
[8] Источник: https://habrahabr.ru/post/323066/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.