Обещание — это способ обработки асинхронных операций. JavaScript — это однопоточный язык, а это означает, что операции могут выполняться только по одной за раз. Это большая проблема, если в вашем коде есть сложные задачи. Вы не хотите, чтобы ваш пользователь не мог щелкнуть или прокрутить или использовать остальную часть вашей программы, пока они ждут завершения операции с большими объемами данных, такой как получение данных с сервера. Позвольте мне привести вам, по общему признанию, вымученную аналогию:
Вы идете в булочную, чтобы заказать себе торт «Красный бархат», потому что вы взрослый человек, и никто не может сказать вам «нет». Но после того, как вы его закажете, вы просто должны стоять там, пока пекарь смешивает все ингредиенты, а затем ставит его в духовку, а затем вы оба (и любые бедолаги позади вас) должны стоять неподвижно 30–32. минут, пока пирог печется. Затем все ждут пару часов, пока торт остынет. Затем пекарь начинает делать глазурь и т. д. и т. д., пока, наконец, следующий человек в очереди не закажет свой торт.
Если бы вы (будучи супер-приятным, неконфликтным человеком) были в этой пекарне, вы, вероятно, сказали бы что-то вроде: Я говорю с вашим менеджером? Конечно, вам придется подождать в конце очереди, чтобы сказать это.
До того, как Promise
был представлен в ES6, способ, которым JavaScript обрабатывал ограничения однопоточности, заключался в асинхронных функциях обратного вызова. По сути, как только операция была завершена, выполнялась функция, сообщающая программе, что данные готовы, и программа немедленно реагировала, делая с данными то, что должна была делать. Есть несколько проблем с этим подходом. Во-первых, в эти асинхронные функции входит много кода. Это может очень быстро привести к «аду обратных вызовов», когда ваш код начинает превращаться в беспорядочную кашу, и чем больше беспорядка в вашем коде, тем труднее его читать, а чем труднее его читать, тем сложнее он становится. для отладки. Кроме того, зависимость от расписания сервера затрудняет оптимизацию вашего приложения, потому что вы не знаете, когда операция будет завершена. (В нашей аналогии с тортом, независимо от того, что вы делаете, вам придется бежать обратно в пекарню, чтобы немедленно забрать свой торт. Я имею в виду, что, если бы вы чувствовали, что вам нужно больше времени, чтобы выполнить какую-то другую задачу, например, закончить финал FBoy Island?)
Не лучше ли было бы, если бы кассир выдал вам квитанцию или обещание, что вы могли бы принести обратно в пекарню и обменять на вкуснейшее сливочное сырное блюдо на вашей расписание?
Вот тут-то и появляются обещания. MDN описывает обещание как объект, представляющий возможное завершение (или сбой) асинхронной операции и ее результирующее значение. Обещания дают разработчикам возможность проектировать свои приложения с более искусным контролем над тем, что и когда отображается на странице, чтобы обеспечить наилучшее взаимодействие с пользователем. Мы не хотим, чтобы кто-то неуклюже, но вежливо спрашивал менеджера.
Анатомия обещания
Есть две фазы использования промисов: «производство» и «потребление».
Фаза «производства» — это создание экземпляра newPromise
с использованием ключевого слова new
. Класс принимает только один параметр — функцию. Функция принимает два параметра, resolve
и reject
. Внутри функции выполняются операции. Если все пойдет по плану, звоните resolve
. Если нет, звоните reject
.
В приведенном выше примере, если значение x
разрешается равным 4, вызовите myResolve
с аргументом строки ‘We did it!’
. Если каким-то образом значение x
не преобразуется в 4, результатом будет myReject
с аргументом errorObject
.
Но помните, myPromise
— это не функция, это экземпляр объекта. Итак, как мы его используем?
Цепочка обещаний
Поскольку обещание является объектом, мы можем связать с ним другие методы. Поведение этих методов будет меняться в зависимости от того, было ли обещание выполнено или отклонено. Это называется «потреблением» обещания. Фактически, большая часть вашего взаимодействия с промисами будет происходить на этапе «потребления», а не на этапе «производства». Для этого мы используем методы .then()
и .catch
.
Метод .then()
принимает два параметра: функцию, которая будет вызываться, если обещание выполнено, и функцию, которая будет вызываться, если обещание отклонено. Метод будет вызываться вне зависимости от того, выполнено обещание или нет.
Метод .catch()
принимает только один параметр — функцию, которая будет вызываться, если обещание было отклонено. Обычно это используется вместо передачи второго параметра в .then()
.
Взгляните на следующий код:
Использование объекта myPromise в том виде, в котором он написан, приведет к тому, что 'We did it!’
будет выведено на консоль. Это так просто!
Вы можете связать столько вызовов .then()
с вашим промисом, и каждый из них будет выполняться только один раз, но независимо от того, сколько вызовов .chain()
вы добавите в конец, будет выполнен только первый (если вы не перебросите аргумент, но это это особый случай. Да ладно, я сказал вам, что это было введение).
В заключение
Промисы — это эффективный способ аккуратно и эффективно справиться с ограничениями однопоточной природы JavaScript. Они широко применяются многими программистами и являются отличным инструментом в наборе инструментов любого разработчика.