Как поместить результат Promise (JS) в переменную? [дубликат]
А в чём смысл такого варианта, если в res.render попадёт 3 значения undefined ? Ведь корректные значения переменным присваиваются в then , а значит, асинхронно и позже.
8 окт 2017 в 6:35
@Regent вопрос был не об этом Добавьте свой вариант
8 окт 2017 в 6:46
тут нужен Promise.all или тупо цепочка обещаний, а не эти костыли
8 окт 2017 в 6:52
- javascript
- promise
- knex.js
-
Важное на Мете
Связанные
Похожие
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.11.21.1314
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Как записать результат промиса в переменную
Ранее мы рассмотрели, как из функции промиса мы можем передать во вне результат асинхронной операции:
const myPromise = new Promise(function(resolve)< console.log("Выполнение асинхронной операции"); resolve("Привет мир!"); >);
Теперь получим это значение. Для получения результата операции промиса применяется функция then() объекта Promise :
then(onFulfilled, onRejected);
Первый параметр функции — onFulfilled представляет функцию, которая выполняется при успешном завершении промиса и в качестве параметра получает переданные в resolve() данные.
Второй параметр функции — onRejected представляет функцию, которая выполняется при возникновении ошибки и в качестве параметра получает переданные в reject() данные.
Функция then() возвращает также объект Promise .
Так, получим переданные данные:
const myPromise = new Promise(function(resolve)< console.log("Выполнение асинхронной операции"); resolve("Привет мир!"); >); myPromise.then(function(value)< console.log(`Из промиса получены данные: $`); >)
То есть параметр value здесь будет представлять строку «Привет мир!» , которая передается в resolve(«Привет мир!») . В итоге консольный вывод будет выглядеть следующим образом:
Выполнение асинхронной операции Из промиса получены данные: Привет мир!
Для примера вызове несколько промисов, чтобы увидеть асинхронность в деле:
const myPromise3000 = new Promise(function(resolve)< console.log("[myPromise3000] Выполнение асинхронной операции"); setTimeout(()=>, 3000); >); const myPromise1000 = new Promise(function(resolve)< console.log("[myPromise1000] Выполнение асинхронной операции"); setTimeout(()=>, 1000); >); const myPromise2000 = new Promise(function(resolve)< console.log("[myPromise2000] Выполнение асинхронной операции"); setTimeout(()=>, 2000); >); myPromise3000.then((value)=>console.log(value)); myPromise1000.then((value)=>console.log(value)); myPromise2000.then((value)=>console.log(value));
Здесь определены три однотипных промиса. Чтобы каждый из них не выполнялся сразу, они используют функцию setTimeout и устанавливают возвращаемое значение только через несколько секунд. Для разных промисов длительность задержки различается. И в данном случае мы получим следующий консольный вывод:
[myPromise3000] Выполнение асинхронной операции [myPromise1000] Выполнение асинхронной операции [myPromise2000] Выполнение асинхронной операции [myPromise1000] Привет мир! [myPromise2000] Привет мир! [myPromise3000] Привет мир!
Здесь мы видим, что первым начал выполняться промис myPromise3000, однако он же завершился последним, так как для него установлено наибольшее время задержки — 3 секунды. Однако его задержка не помешала выполнению остальных промисов.
При этом нам необязательно вообще передавать в resolve() какое-либо значение. Возможно, асинхронная операция просто выполняется и передает во вне никакого результата.
const x = 4; const y = 8; const myPromise = new Promise(function()< console.log("Выполнение асинхронной операции"); const z = x + y; console.log(`Результат операции: $`) >); myPromise.then();
В данном случае функция в промисе вычисляет сумму чисел x и y и выводит результат на консоль.
Метод Promise.resolve
Иногда требуется просто вернуть из промиса некоторое значение. Для этого можно использовать метод Promise.resolve() . В этот метод передается возвращаемое из промиса значение. Метод Promise.resolve() возвращает объект Promise:
const myPromise = Promise.resolve("Привет мир!"); myPromise.then(value => console.log(value)); // Привет мир!
Определение промиса через функцию
Нередко промис определяется через функцию, которая возвращет объект Promise. Например:
function sum(x, y)< return new Promise(function(resolve)< const result = x + y; resolve(result); >) > sum(3, 5).then(function(value)< console.log("Результат операции:", value);>); sum(25, 4).then(function(value)< console.log("Сумма чисел:", value);>);
Здесь функция sum() принимает два числа и возвращает промис, который инкапсулирует операцию сумму этих чисел. После вычисления сумма чисел передается в resolve() , соответственно мы ее затем можем получить через метод then() . Определение промиса через функцию позволяет нам, с одной стороны, при вызове функции передавать разные значения. А с другой стороны, работать с результатом этой функции как с промисом и настроить при каждом конкретном вызове обработку полученного значения.
Результат работы программы:
Результат операции: 8 Сумма чисел: 29
Однако, что если у нас совпадает принцип обработки полученного из асинхронной функции значения?
sum(3, 5).then(function(value)< console.log("Результат операции:", value);>); sum(25, 4).then(function(value)< console.log("Результат операции:", value);>);
В этом случае логика обработки будет повторяться. Но поскольку метод then() также возвращает объект Promise, то мы можем сделать следующим образом:
function sum(x, y)< return new Promise(function(resolve)< const result = x + y; resolve(result); >).then(function(value)< console.log("Результат операции:", value);>); > sum(3, 5); sum(25, 4);
Гибкая настройка функции
А что, если мы хотим, чтобы у программиста был выбор: если он хочет, то может определить свой обработчик, а если нет, то применяется некоторый обработчик по умолчанию. В этом случае мы можем определить функцию обработчика в качестве параметра функции, а если он не передан, то устанавливать обработчик по умолчанию:
function sum(x, y, func)< // если обработчик не установлен, то устанавливаем обработчик по умолчанию if(func===undefined) func = function(value)< console.log("Результат операции:", value);>; return new Promise(function(resolve)< const result = x + y; resolve(result); >).then(func); > sum(3, 5); sum(25, 4, function(value)< console.log("Сумма:", value);>);
Здесь при первом вызове функции sum() ( sum(3, 5) ) будет срабатывать обработчик по умолчанию. Во втором случае обработчик явным образом передается через третий параметр, соответственно он будет задействован sum(25, 4, function(value)< console.log("Сумма:", value);>)
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.
Promise — краткое руководство
Цель данной статьи рассказать о жизненном цикле Promise и о отличиях методов all vs any vs race vs allSettled.
В данном тексте нет ничего супернаучного, поэтому могу предположить что статья расчитана на Junior+.
Кратко
new Promise(resolve, reject) => <>) .then(onFulfilled, onRejected) .catch(onRejected); Promise.all(array); Promise.any(array); Promise.race(array); Promise.allSettled(array)
Жизненный цикл Promise
Исходя из документации мы можем говорить что инстанс Promise имеет несколько динамически изменяемых сущностей:
- State - может быть в трех состояниях, pending , fulfilled и rejected ;
- Fate - бывает в двух состояниях, unresolved или resolved ;
- Settled - имеет два состояния settled и unsettled .
Cразу после создания, промис находится в состоянии pending , следующим шагом может быть три варианта, первые два которые я упомяну это resolve(any) и reject(any) , последним мы разберем resolve(thenable) .
- resolve(any) - переводим промис в состояние fulfilled , вызываем onFulfilled ;
- reject(any) - переводим промис в состояние rejected , вызываем onRejected ;
- resolve(promise) - если в качестве аргумента мы передадим в resolve другой промис то мы отложим resolve основного промиса до тех пор, пока не выполнится вложенный, а точнее пока он не станет settled , т.е. пока не перейдет в состояние fulfilled или rejected .
состояние
завершен ?
установлен ?
new Promise()
resolve(promise)
resolve(any)
reject(any)
Состояние - это сущность промиса, которая изменяется на протяжении его жизни в направлении от pending до fulfilled или rejected.
Завершен - это сущность промиса которая говорит о том, завершена ли работа текущего промиса (resolved), которая определяется вызовом метода resolve или reject, важно понимать что завершение работы не значит что значение установлено.
Установлен - это сущность промиса которая говорит о том, установлено ли значение для этого промиса, речь идёт о аргументах переданных в resolve или reject.
Отдельное внимание стоит обратить на случай, когда в качестве аргумента, в resolve передаётся значения в виде thenable объекта, в таком случае состояние основного промиса остается pending но при этом основной промис считается resolved, дальнейшая судьба основного промиса перекладывается на этот новый объект, и "значение" основного промиса будет равно "значению" thenable.
Сравнение all vs any vs race vs allSettled
Несколько промисов в один можно объеденить c помощью статических методов класса Promise:
- all - нужны все выполненные
- дожидаемся пока все промисы из array будут выполнены , в onFulfilled мы получаем массив результатов в том же порядке в каком были установлены промисы в начальном массиве;
- в случае если хоть один промис из array будет отклонён , в onRejected мы получим причину первого отклоненного промиса.
- дожидаемся когда хотя бы один промис из array выполнится , в onFulfilled мы получаем результат первого выполненного промиса;
- в случае если все промисы из array будут отклонены , в onRejected мы получим AggregateError: All promises were rejected.
- дожидаемся когда любой промис из array выполнится или отклонится , в onFulfilled мы получим результат первого такого промиса.
- дожидаемся пока все промисы из array будут завершены , в onFulfilled мы получаем массив результатов в том же порядке в каком были установлены промисы в начальном массиве.
all
any
race
allSettled
если аргумент пустой массив
становится fulfilled
когдавсе resolved
или
один rejectedодин resolved
или
все rejectedодин resolved
или
один rejectedвсе resolved
и
все rejectedвозвращает в коллбэк в случае fulfilled
все resolved
или
первый rejectedпервый resolved
или
первый rejectedвсе resolved
и
все rejectedПояснение: метод all
- Если в метод all передать пустой массив Promise.all([]) , то возвращаемый методом all промис становится fulfilled так как у него нет ни одного rejected промиса.
- Если в метод all передать массив с промисами Promise.all([. ]) , то возвращаемый методом all промис становится fulfilled в двух случаях: если все промисы в массиве будут resolved или хотя бы один будет rejected.
- Если возвращаемый методом all промис становится fulfilled то в соответствующий коллбэк отправляется массив данных от всех resolved промисов или данные от одногоrejected промиса.
Пояснение: метод any
- Если в метод any передать пустой массив Promise.any([]) , то возвращаемый методом any промис становится rejected так как у него нет ни одного fulfilled промиса.
- Если в метод any передать массив с промисами Promise.any([. ]) , то возвращаемый методом any промис становится fulfilled в двух случаях: если хотя бы один будет resolved или все промисы в массиве будут rejected.
- Если возвращаемый методом any промис становится fulfilled то в соответствующий коллбэк отправляется данные от первого resolved промиса или AggregateError так ни один промис не закончился успешно.
Пояснение: метод race
- Если в метод race передать пустой массив Promise.race([]) , то возвращаемый методом race промис остается pending так как у него нет ни одного fulfilled промиса.
- Если в метод race передать массив с промисами Promise.race([. ]) , то возвращаемый методом race промис остается pending до тех пор пока хотя бы один промис в массиве не станет resolved или rejected.
- Если возвращаемый методом race промис становится fulfilled то в соответствующий коллбэк отправляется данные от первого resolved или первогоrejected промиса.
Пояснение: метод allSettled
- Если в метод allSettled передать пустой массив Promise.allSettled([]) , то возвращаемый методом allSettled промис становится fulfilled.
- Если в метод allSettled передать массив с промисами Promise.allSettled([. ]) , то возвращаемый методом allSettled промис становится fulfilled в случае: если все промисы в массиве будут settled.
- Если возвращаемый методом allSettled промис становится fulfilled то в соответствующий коллбэк отправляется массив данных от всех settled промисов.
- javascript
- promise
- promise.all()
- promise.any()
- promise.race()
- promise.allSettled()
- жизненный цикл
