Перевод «on promises» на русский
Under no circumstances should you rely on promises or the routine you have created in your relationship.
Ни при каких обстоятельствах вы не должны полагаться на обещания или рутину, которую вы создали в своих отношениях.
In business, you can’t rely on promises.
В бизнесе вы не можете полагаться на обещания.
The EU has made clear there can be no backsliding on promises made in the first round of talks.
ЕС также дал понять, что отступление от обещаний, сделанных в первом раунде переговоров, невозможно.
As many a weary trade negotiator can attest, China has a history of reneging on promises.
Как могут засвидетельствовать многие утомленные участники торговых переговоров, у Китая есть история отказа от обещаний.
The whole industry is built on promises.
Здесь весь бизнес построен на обещаниях.
Democratic politics and modern policymaking are based on promises.
Демократическая политика и современный «полисимейкинг» базируются на обещаниях.
It’s all built on promises.
Здесь весь бизнес построен на обещаниях.
Many medical startups have earned billions on promises to create new methods of treating and preventing diseases.
Многие компании заработали миллиарды на обещаниях создать новые методы лечения и профилактики болезней.
They are partially implemented and roughly speaking is based on promises of a bright future.
Они реализованы частично и держатся, грубо говоря, на обещаниях светлого будущего.
By this point, this evaluation of these potential SEO service providers has been based on promises and negotiations about future content.
К этому моменту оценка потенциальных поставщиков услуг SEO была основана на обещаниях и переговорах о будущем контенте.
This, too, undermines Putin’s power, which relies on promises of economic prosperity.
Это тоже подрывает власть Путина, который опирается на обещания экономического процветания.
Speeches of Barack Obama are built on promises and phrases that people want to hear, and it certainly effectively influences the mass consciousness.
Выступления Барака Обамы построены на обещаниях и на фразах, которые хочет услышать население, и это, безусловно, эффективно воздействует на массовое сознание.
I was an American girl, raised on promises.
«Она была американской девушкой, воспитанной на обещаниях«.
As President Medvedev has recently stated, «national security cannot depend just on promises«.
Как недавно сказал в своем выступлении президент Д.А.Медведев: «национальная безопасность не может основываться только на обещаниях«.
In reneging on promises of reform and further market opening, President Xi Jinping is reinforcing the state sector against foreign competition while ignoring intellectual property theft.
Отказываясь от обещаний реформы и дальнейшего открытия рынка Президент Си Цзиньпин усиливает государственный сектор по отношению к иностранной конкуренции, игнорируя при этом кражу интеллектуальной собственности.
Promise
Объект Promise используется для отложенных и асинхронных вычислений.
Интерактивный пример
Синтаксис
new Promise(executor); new Promise(function(resolve, reject) . >);
Параметры
Объект функции с двумя аргументами resolve и reject . Функция executor получает оба аргумента и выполняется сразу, ещё до того как конструктор вернёт созданный объект. Первый аргумент ( resolve ) вызывает успешное исполнение промиса, второй ( reject ) отклоняет его. Обычно функция executor описывает выполнение какой-то асинхронной работы, по завершении которой необходимо вызвать функцию resolve или reject . Обратите внимание, что возвращаемое значение функции executor игнорируется.
Описание
Интерфейс Promise (промис) представляет собой обёртку для значения, неизвестного на момент создания промиса. Он позволяет обрабатывать результаты асинхронных операций так, как если бы они были синхронными: вместо конечного результата асинхронного метода возвращается своего рода обещание (дословный перевод слова «промис») получить результат в некоторый момент в будущем.
Promise может находиться в трёх состояниях:
- ожидание (pending): начальное состояние, не исполнен и не отклонён.
- исполнено (fulfilled): операция завершена успешно.
- отклонено (rejected): операция завершена с ошибкой.
При создании промис находится в ожидании (pending), а затем может стать исполненным (fulfilled), вернув полученный результат (значение), или отклонённым (rejected), вернув причину отказа. В любом из этих случаев вызывается обработчик, прикреплённый к промису методом then . (Если в момент назначения обработчика промис уже исполнен или отклонён, обработчик всё равно будет вызван, т.е. асинхронное исполнение промиса и назначение обработчика не будет происходить в «состоянии гонки», как, например, в случае с событиями в DOM.)
Так как методы Promise.prototype.then() и Promise.prototype.catch() сами возвращают промис, их можно вызывать цепочкой, создавая соединения.
Примечание: говорят, что промис находится в состоянии завершён (settled) когда он или исполнен или отклонён, т.е. в любом состоянии, кроме ожидания (это лишь форма речи, не являющаяся настоящим состоянием промиса). Также можно встретить термин исполнен (resolved) — это значит что промис завершён или «заблокирован» в ожидании завершения другого промиса. В статье состояния и fates приводится более подробное описание терминологии.
Свойства
Значение свойства всегда равно 1 (количество аргументов конструктора).
Представляет прототип для конструктора Promise .
Методы
Ожидает исполнения всех промисов или отклонения любого из них.
Возвращает промис, который исполнится после исполнения всех промисов в iterable . В случае, если любой из промисов будет отклонён, Promise.all будет также отклонён.
Ожидает завершения всех полученных промисов (как исполнения так и отклонения).
Возвращает промис, который исполняется когда все полученные промисы завершены (исполнены или отклонены), содержащий массив результатов исполнения полученных промисов.
Ожидает исполнения или отклонения любого из полученных промисов.
Возвращает промис, который будет исполнен или отклонён с результатом исполнения первого исполненного или отклонённого промиса из iterable .
Возвращает промис, отклонённый из-за reason .
Возвращает промис, исполненный с результатом value .
Создание промиса
Объект Promise создаётся при помощи ключевого слова new и своего конструктора. Конструктор Promise принимает в качестве аргумента функцию, называемую «исполнитель» (executor function). Эта функция должна принимать две функции-колбэка в качестве параметров. Первый из них ( resolve ) вызывается, когда асинхронная операция завершилась успешно и вернула результат своего исполнения в виде значения. Второй колбэк ( reject ) вызывается, когда операция не удалась, и возвращает значение, указывающее на причину неудачи, чаще всего объект ошибки.
const myFirstPromise = new Promise((resolve, reject) => // выполняется асинхронная операция, которая в итоге вызовет: // // resolve(someValue); // успешное завершение // или // reject("failure reason"); // неудача >);
Чтобы снабдить функцию функциональностью промисов, нужно просто вернуть в ней объект Promise :
function myAsyncFunction(url) return new Promise((resolve, reject) => const xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.onload = () => resolve(xhr.responseText); xhr.onerror = () => reject(xhr.statusText); xhr.send(); >); >
Примеры
Простой пример
js
let myFirstPromise = new Promise((resolve, reject) => // Мы вызываем resolve(. ), когда асинхронная операция завершилась успешно, и reject(. ), когда она не удалась. // В этом примере мы используем setTimeout(. ), чтобы симулировать асинхронный код. // В реальности вы, скорее всего, будете использовать XHR, HTML5 API или что-то подобное. setTimeout(function () resolve("Success!"); // Ура! Всё прошло хорошо! >, 250); >); myFirstPromise.then((successMessage) => // successMessage - это что угодно, что мы передали в функцию resolve(. ) выше. // Это необязательно строка, но если это всего лишь сообщение об успешном завершении, это наверняка будет она. console.log("Ура! " + successMessage); >);Продвинутый пример
html
button id="btn">Создать Promise!button> div id="log">div>исполнение промиса протоколируется при помощи продолжения p1.then . Это показывает как синхронная часть метода отвязана от асинхронного завершения промиса.
var promiseCount = 0; function testPromise() var thisPromiseCount = ++promiseCount; var log = document.getElementById('log'); log.insertAdjacentHTML('beforeend', thisPromiseCount + ') Запуск (запуск синхронного кода) '); // Создаём промис, возвращающее 'result' (по истечении 3-х секунд) var p1 = new Promise( // Функция разрешения позволяет завершить успешно или // отклонить промис function(resolve, reject) log.insertAdjacentHTML('beforeend', thisPromiseCount + ') Запуск промиса (запуск асинхронного кода) '); // Это всего лишь пример асинхронности window.setTimeout( function() // Промис исполнен! resolve(thisPromiseCount) >, Math.random() * 2000 + 1000); >); // Указываем, что сделать с исполненным промисом p1.then( // Записываем в протокол function(val) log.insertAdjacentHTML('beforeend', val + ') Промис исполнен (асинхронный код завершён) '); >); log.insertAdjacentHTML('beforeend', thisPromiseCount + ') Промис создан (синхронный код завершён) '); >if ("Promise" in window) btn = document.getElementById("btn"); btn.addEventListener("click", testPromise); > else log = document.getElementById("log"); log.innerHTML = "Live example not available as your browser doesn't support the Promise interface."; >if ("Promise" in window) let btn = document.getElementById("btn"); btn.addEventListener("click", testPromise); > else log = document.getElementById("log"); log.innerHTML = "Демонстрация невозможна, поскольку ваш браузер не поддерживает интерфейсPromise; >."Данный пример запускается при нажатии на кнопку. Для этого вам необходим браузер, поддерживающий Promise . При последовательных нажатиях на кнопку с коротким интервалом, вы можете увидеть как различные промиса будут исполнены один за другим.
Загрузка изображения при помощи XHR
Другой простой пример использования Promise и XMLHttpRequest для загрузки изображения доступен в репозитории MDNpromise-test на GitHub. Вы также можете посмотреть его в действии. Каждый шаг прокомментирован и вы можете подробно исследовать Promise и XHR.
Спецификации
| Specification |
|---|
| ECMAScript Language Specification # sec-promise-objects |
Совместимость с браузерами
BCD tables only load in the browser
Смотрите также
- Спецификация Promises/A+
- Jake Archibald: JavaScript Promises: There and Back Again
- Domenic Denicola: Callbacks, Promises, and Coroutines – Asynchronous Programming Pattern in JavaScript
- Matt Greer: JavaScript Promises . In Wicked Detail
- Forbes Lindesay: promisejs.org
- Nolan Lawson: We have a problem with promises — Common mistakes with promises
- Promise polyfill
- Udacity: JavaScript Promises
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
This page was last modified on 7 авг. 2023 г. by MDN contributors.
Your blueprint for a better internet.
On promise что это
Промис (promise) - это объект, представляющий результат успешного или неудачного завершения асинхронной операции. Асинхронная операция, упрощенно говоря, это некоторое действие, выполняется независимо от окружающего ее кода, в котором она вызывается, не блокирует выполнение вызываемого кода.
Промис может находиться в одном из следующих состояний:
- pending (состояние ожидания): начальное состояние, промис создан, но выполнение еще не завершено
- fulfilled (успешно завершено): действие, которое представляет промис, успешно завершено
- rejected (завершено с ошибкой): при выполнении действия, которое представляет промис, произошла ошибка
Для создания промиса применяется конструктор типа Promise :
new Promise(executor)
В качестве параметра конструктор принимает функцию, которая выполняется при создании промиса. Обычно эта функция представляет асинхронные операции, которые занимают продолжительное время. Например, определим простейший промис:
const myPromise = new Promise(function()< console.log("Выполнение асинхронной операции"); >);
Здесь функция просто выводит на консоль сообщение. Соответственно при выполнении этого кода мы увидим на консоли сообщение "Выполнение асинхронной операции" .
При создании промиса, когда его функция еще не начала выполняться, промис переходит в состояние "pending", то есть ожидает выполнения.
Для эмуляции асинхронности определим несколько промисов:
const myPromise3000 = new Promise(function()< console.log("[myPromise3000] Выполнение асинхронной операции"); setTimeout(()=>console.log("[myPromise3000] Завершение асинхронной операции"), 3000); >); const myPromise1000 = new Promise(function()< console.log("[myPromise1000] Выполнение асинхронной операции"); setTimeout(()=>console.log("[myPromise1000] Завершение асинхронной операции"), 1000); >); const myPromise2000 = new Promise(function()< console.log("[myPromise2000] Выполнение асинхронной операции"); setTimeout(()=>console.log("[myPromise2000] Завершение асинхронной операции"), 2000); >);
Здесь определены три однотипных промиса. Чтобы каждый из них не выполнялся сразу, они используют функцию setTimeout с задержкой в несколько секунд. Для разных промисов длительность задержки различается. И в данном случае мы получим следующий консольный вывод:
[myPromise3000] Выполнение асинхронной операции [myPromise1000] Выполнение асинхронной операции [myPromise2000] Выполнение асинхронной операции [myPromise1000] Завершение асинхронной операции [myPromise2000] Завершение асинхронной операции [myPromise3000] Завершение асинхронной операции
Здесь мы видим, что первым начал выполняться промис myPromise3000, однако он же завершился последним, так как для него установлено наибольшее время задержки - 3 секунды. Однако его задержка не помешала выполнению остальных промисов.
resolve и reject
Как правило, функция, которая передается в конструктор Promise, принимает два параметра:
const myPromise = new Promise(function(resolve, reject)< console.log("Выполнение асинхронной операции"); >);
Оба этих параметра - resolve и reject также представляют функции. И каждая из этих функций принимает параметр любого типа.
Первый параметр - функция resolve вызывается в случае успешного выполнения. Мы можем в нее передать значение, которое мы можем получить в результате успешного выполнения.
Второй параметр - функция reject вызывается, если выполнение операции завершилось с ошибкой. Мы можем в нее передать значение, которое представит некоторую информацию об ошибке.
Успешное выполнение промиса
Итак, первый параметр функции в конструкторе Promise - функция resolve выполняется при успешном выполненим. В эту функцию обычно передается значение, которое представляет результат операции при успешном выполнении. Это значение может представлять любой объект. Например, передадим в эту функцию строку:
const myPromise = new Promise(function(resolve)< console.log("Выполнение асинхронной операции"); resolve("Привет мир!"); >);
Функция resolve() вызывается в конце выполняемой операции после всех действий. При вызове этой функции промис переходит в состояние fulfilled (успешно выполнено).
При этом стоит отметить, что теоретически мы можем возвратить из функции результат, но практического смысла в этом не будет:
const myPromise = new Promise(function(resolve, reject)< console.log("Выполнение асинхронной операции"); return "Привет мир!"; >);
Данное возвращаемое значение мы не сможем передать во вне. И если действительно надо возвратить какой-то результат, то он передается в функцию resolve() .
Передача информации об ошибке
Второй параметр функции в конструкторе Promise - функция reject вызывается при возникновении ошибки. В эту функцию обычно передается некоторая информация об ошибке, которое может представлять любой объект. Например:
const myPromise = new Promise(function(resolve, reject)< console.log("Выполнение асинхронной операции"); reject("Переданы некорректные данные"); >);
При вызове функции reject() промис переходит в состояние rejected (завершилось с ошибкой).
Объединение resolve и reject
Естественно мы можем определить логику, при которой в зависимости от условий будут выполняться обе функции:
const x = 4; const y = 0; const myPromise = new Promise(function(resolve, reject) < if(y === 0) < reject("Переданы некорректные данные"); >else < const z = x / y; resolve(z); >>);
В данном случае, если значени константы y равно 0, то сообщаем об ошибке, вызывая функцию reject() . Если не равно 0, то выполняем операцию деления и передаем результат в функцию resolve() .
Использование промисов
Promise (промис) - это объект, представляющий результат успешного или неудачного завершения асинхронной операции. Так как большинство людей пользуются уже созданными промисами, это руководство начнём с объяснения использования вернувшихся промисов до объяснения принципов создания.
В сущности, промис - это возвращаемый объект, в который вы записываете два колбэка вместо того, чтобы передать их функции.
Например, вместо старомодной функции, которая принимает два колбэка и вызывает один из них в зависимости от успешного или неудачного завершения операции:
function doSomethingOldStyle(successCallback, failureCallback) console.log("Готово."); // Успех в половине случаев. if (Math.random() > 0.5) successCallback("Успех"); > else failureCallback("Ошибка"); > > function successCallback(result) console.log("Успешно завершено с результатом " + result); > function failureCallback(error) console.log("Завершено с ошибкой " + error); > doSomethingOldStyle(successCallback, failureCallback);
…современные функции возвращают промис, в который вы записываете ваши колбэки:
function doSomething() return new Promise((resolve, reject) => console.log("Готово."); // Успех в половине случаев. if (Math.random() > 0.5) resolve("Успех"); > else reject("Ошибка"); > >); > const promise = doSomething(); promise.then(successCallback, failureCallback);
doSomething().then(successCallback, failureCallback);
Мы называем это асинхронным вызовом функции. У этого соглашения есть несколько преимуществ. Давайте рассмотрим их.
Гарантии
В отличие от старомодных переданных колбэков промис даёт некоторые гарантии:
- Колбэки никогда не будут вызваны до завершения обработки текущего события в событийном цикле JavaScript.
- Колбэки, добавленные через .then даже после успешного или неудачного завершения асинхронной операции, будут также вызваны.
- Несколько колбэков может быть добавлено вызовом .then нужное количество раз, и они будут выполняться независимо в порядке добавления.
Но наиболее непосредственная польза от промисов - цепочка вызовов (chaining).
Цепочка вызовов
Общая нужда - выполнять две или более асинхронных операции одна за другой, причём каждая следующая начинается при успешном завершении предыдущей и использует результат её выполнения. Мы реализуем это, создавая цепочку вызовов промисов (promise chain).
Вот в чём магия: функция then возвращает новый промис, отличающийся от первоначального:
let promise = doSomething(); let promise2 = promise.then(successCallback, failureCallback);
let promise2 = doSomething().then(successCallback, failureCallback);
Второй промис представляет завершение не только doSomething() , но и функций successCallback или failureCallback , переданных вами, а они тоже могут быть асинхронными функциями, возвращающими промис. В этом случае все колбэки, добавленные к promise2 будут поставлены в очередь за промисом, возвращаемым successCallback или failureCallback .
По сути, каждый вызванный промис означает успешное завершение предыдущих шагов в цепочке.
Раньше выполнение нескольких асинхронных операций друг за другом приводило к классической "Вавилонской башне" колбэков:
doSomething(function (result) doSomethingElse( result, function (newResult) doThirdThing( newResult, function (finalResult) console.log("Итоговый результат: " + finalResult); >, failureCallback, ); >, failureCallback, ); >, failureCallback);
В современных функциях мы записываем колбэки в возвращаемые промисы - формируем цепочку промисов:
doSomething() .then(function (result) return doSomethingElse(result); >) .then(function (newResult) return doThirdThing(newResult); >) .then(function (finalResult) console.log("Итоговый результат: " + finalResult); >) .catch(failureCallback);
Аргументы then необязательны, а catch(failureCallback) - это сокращение для then(null, failureCallback) . Вот как это выражено с помощью стрелочных функций:
doSomething() .then((result) => doSomethingElse(result)) .then((newResult) => doThirdThing(newResult)) .then((finalResult) => console.log(`Итоговый результат: $finalResult>`); >) .catch(failureCallback);
Важно: Всегда возвращайте промисы в return, иначе колбэки не будут сцеплены и ошибки могут быть не пойманы (стрелочные функции неявно возвращают результат, если скобки <> вокруг тела функции опущены).
Цепочка вызовов после catch
Можно продолжить цепочку вызовов после ошибки, т. е. после catch , что полезно для выполнения новых действий даже после того, как действие вернёт ошибку в цепочке вызовов. Ниже приведён пример:
new Promise((resolve, reject) => < console.log('Начало'); resolve(); >) .then(() => < throw new Error('Где-то произошла ошибка'); console.log('Выведи это'); >) .catch(() => < console.log('Выведи то'); >) .then(() => < console.log('Выведи это, несмотря ни на что'); >);
В результате выведется данный текст:
Начало Выведи то Выведи это, несмотря ни на что
Заметьте, что текст "Выведи это" не вывелся, потому что "Где-то произошла ошибка" привела к отказу
Распространение ошибки
Вы могли ранее заметить, что failureCallback повторяется три раза в "pyramid of doom", а в цепочке промисов всего лишь один раз:
doSomething() .then(result => doSomethingElse(result)) .then(newResult => doThirdThing(newResult)) .then(finalResult => console.log(`Итоговый результат: $`)) .catch(failureCallback);
В основном, цепочка промисов останавливает выполнение кода, если где-либо произошла ошибка, и вместо этого ищет далее по цепочке обработчики ошибок. Это очень похоже на то, как работает синхронный код:
try < let result = syncDoSomething(); let newResult = syncDoSomethingElse(result); let finalResult = syncDoThirdThing(newResult); console.log(`Итоговый результат: $`); > catch(error)
Эта симметрия с синхронным кодом лучше всего показывает себя в синтаксическом сахаре async / await в ECMAScript 2017:
async function foo() < try < let result = await doSomething(); let newResult = await doSomethingElse(result); let finalResult = await doThirdThing(newResult); console.log(`Итоговый результат: $`); > catch(error) < failureCallback(error); >>
Работа данного кода основана на промисах. Для примера здесь используется функция doSomething() , которая встречалась ранее. Вы можете прочитать больше о синтаксисе здесь
Промисы решают основную проблему пирамид, обработку всех ошибок, даже вызовов исключений и программных ошибок. Это основа для функционального построения асинхронных операций.
Создание промиса вокруг старого колбэка
Promise может быть создан с помощью конструктора. Это может понадобится только для старых API.
В идеале, все асинхронные функции уже должны возвращать промис. Но увы, некоторые APIs до сих пор ожидают успешного или неудачного колбэка переданных по старинке. Типичный пример: setTimeout() функция:
setTimeout(() => saySomething("10 seconds passed"), 10000);
Смешивание старого колбэк-стиля и промисов проблематично. В случае неудачного завершения saySomething или программной ошибки, нельзя обработать ошибку.
К счастью мы можем обернуть функцию в промис. Хороший тон оборачивать проблематичные функции на самом низком возможном уровне, и больше никогда их не вызывать напрямую:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms)); wait(10000).then(() => saySomething("10 seconds")).catch(failureCallback);
В сущности, конструктор промиса становится исполнителем функции, который позволяет нам резолвить или режектить промис вручную. Так как setTimeout всегда успешен, мы опустили reject в этом случае.
Композиция
Promise.resolve() и Promise.reject() короткий способ создать уже успешные или отклонённые промисы соответственно. Это иногда бывает полезно.
Promise.all() и Promise.race() - два метода запустить асинхронные операции параллельно.
Последовательное выполнение композиции возможно при помощи хитрости JavaScript:
[func1, func2].reduce((p, f) => p.then(f), Promise.resolve());
Фактически, мы превращаем массив асинхронных функций в цепочку промисов равносильно: Promise.resolve().then(func1).then(func2);
Это также можно сделать, объединив композицию в функцию, в функциональном стиле программирования:
const applyAsync = (acc,val) => acc.then(val); const composeAsync = (. funcs) => x => funcs.reduce(applyAsync, Promise.resolve(x));
composeAsync функция примет любое количество функций в качестве аргументов и вернёт новую функцию которая примет в параметрах начальное значение, переданное по цепочке. Это удобно, потому что некоторые или все функции могут быть либо асинхронными, либо синхронными, и они гарантированно выполнятся в правильной последовательности:
const transformData = composeAsync(func1, asyncFunc1, asyncFunc2, func2); transformData(data);
В ECMAScript 2017, последовательные композиции могут быть выполнены более простым способом с помощью async/await:
for (const f of [func1, func2])
Порядок выполнения
Чтобы избежать сюрпризов, функции, переданные в then никогда не будут вызваны синхронно, даже с уже разрешённым промисом:
Promise.resolve().then(() => console.log(2)); console.log(1); // 1, 2
Вместо немедленного выполнения, переданная функция встанет в очередь микрозадач, а значит выполнится, когда очередь будет пустой в конце текущего вызова JavaScript цикла событий (event loop), т.е. очень скоро:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms)); wait().then(() => console.log(4)); Promise.resolve().then(() => console.log(2)).then(() => console.log(3)); console.log(1); // 1, 2, 3, 4
Вложенность
Простые цепочки promise лучше оставлять без вложений, так как вложенность может быть результатом небрежной структуры. Смотрите распространённые ошибки.
Вложенность - это управляющая структура, ограничивающая область действия операторов catch. В частности, вложенный catch только перехватывает сбои в своей области и ниже, а не ошибки выше в цепочке за пределами вложенной области. При правильном использовании это даёт большую точность в извлечение ошибок:
doSomethingCritical() .then(result => doSomethingOptional() .then(optionalResult => doSomethingExtraNice(optionalResult)) .catch(e => <>)) // Игнорируется если необязательные параметр не выкинул исключение .then(() => moreCriticalStuff()) .catch(e => console.log("Критическая ошибка: " + e.message));
Обратите внимание, что необязательный шаги здесь выделены отступом.
Внутренний оператор catch нейтрализует и перехватывает ошибки только от doSomethingOptional() и doSomethingExtraNice(), после чего код возобновляется с помощью moreCriticalStuff(). Важно, что в случае сбоя doSomethingCritical() его ошибка перехватывается только последним (внешним) catch.
Частые ошибки
В этом разделе собраны частые ошибки, возникающие при создании цепочек промисов. Несколько таких ошибок можно увидеть в следующем примере:
// Плохой пример! Три ошибки! doSomething().then(function(result) < doSomethingElse(result) // Забыл вернуть промис из внутренней цепочки + неуместное влаживание .then(newResult =>doThirdThing(newResult)); >).then(() => doFourthThing()); // Забыл закончить цепочку методом catch
Первая ошибка это неправильно сцепить вещи между собой. Такое происходит когда мы создаём промис но забываем вернуть его. Как следствие, цепочка сломана, но правильнее было бы сказать что теперь у нас есть две независимые цепочки, соревнующиеся за право разрешится первой. Это означает, что doFourthThing() не будет ждать doSomethingElse() или doThirdThing() пока тот закончится, и будет исполнятся параллельно с ними, это, вероятно, не то что хотел разработчик. Отдельные цепочки также имеют отдельную обработку ошибок, что приводит к необработанным ошибкам.
Вторая ошибка это излишняя вложенность, включая первую ошибку. Вложенность также ограничивает область видимости внутренних обработчиков ошибок, если это не то чего хотел разработчик, это может привести к необработанным ошибкам. Примером этого является пример как не нужно создавать промисы, который комбинирует вложенность с чрезмерным использованием конструктора промисов для оборачивания кода который уже использует промисы.
Третья ошибка это забыть закончить цепочку ключевым словом catch . Незаконченные цепочки приводят к необработанным отторжениям промисов в большинстве браузеров.
Хорошим примером является всегда либо возвращать либо заканчивать цепочки промисов, и как только вы получаете новый промис, возвращайте его сразу же, чтобы не усложнять код излишней вложенностью:
doSomething() .then(function(result) < return doSomethingElse(result); >) .then(newResult => doThirdThing(newResult)) .then(() => doFourthThing()) .catch(error => console.log(error));
Обратите внимание что () => x это сокращённая форма () => < return x; >.
Теперь у нас имеется единственная определённая цепочка с правильной обработкой ошибок.
Использование async / await предотвращает большинство, если не все вышеуказанные ошибки, но взамен появляется другая частая ошибка — забыть ключевое слово await .
Смотрите также
- Promise.then()
- Спецификация Promises/A+ (EN)
- Нолан Лоусон (Nolan Lawson): У нас проблемы с промисами - распространённые ошибки (EN)
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
