1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
|
---
title: Promise
slug: Web/JavaScript/Reference/Global_Objects/Promise
tags:
- ECMAScript6
- JavaScript
- Promise
- Обещания
translation_of: Web/JavaScript/Reference/Global_Objects/Promise
---
<div>{{JSRef}}</div>
<h2 id="Сводка">Сводка</h2>
<p>Объект <strong><code>Promise</code></strong> (промис) используется для отложенных и асинхронных вычислений.</p>
<p>{{EmbedInteractiveExample("pages/js/promise-constructor.html")}}</p>
<div class="hidden">
<p>Исходники интерактивного демо находятся в репозитории на GitHub. Если вы хотите внести свой вклад в развитие интерактивных демо, пожалуйста, склонируйте <a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> и отправьте нам пулреквест.</p>
</div>
<h2 id="Синтаксис">Синтаксис</h2>
<pre class="brush: js">new Promise(<em>executor</em>);
new Promise(function(resolve, reject) { ... });</pre>
<h3 id="Параметры">Параметры</h3>
<dl>
<dt>executor</dt>
<dd>Объект функции с двумя аргументами <code>resolve</code> и <code>reject</code>. Функция <code>executor</code> получает оба аргумента и выполняется сразу, еще до того как конструктор вернет созданный объект. Первый аргумент (<code>resolve</code>) вызывает успешное исполнение промиса, второй (<code>reject</code>) отклоняет его.<br>
Обычно функция <code>executor</code> описывает выполнение какой-то асинхронной работы, по завершении которой необходимо вызвать функцию <code>resolve</code> или <code>reject</code>. Обратите внимание, что возвращаемое значение функции <code>executor</code> игнорируется.</dd>
</dl>
<h2 id="Описание">Описание</h2>
<p>Интерфейс <code><strong>Promise</strong></code> (промис) представляет собой обертку для значения, неизвестного на момент создания промиса. Он позволяет обрабатывать результаты асинхронных операций так, как если бы они были синхронными: вместо конечного результата асинхронного метода возвращается <em>обещание </em>(промис)<em> </em>получить результат в некоторый момент в будущем.</p>
<p><code>Promise</code> может находиться в трёх состояниях:</p>
<ul>
<li><em>ожидание (pending)</em>: начальное состояние, не исполнен и не отклонен.</li>
<li><em>исполнено (fulfilled)</em>: операция завершена успешно.</li>
<li><em>отклонено (rejected)</em>: операция завершена с ошибкой.</li>
</ul>
<p>При создании промис находится в <em>ожидании (pending)</em>, а затем может стать <em>исполненным </em> (<em>fulfilled)</em>, вернув полученный результат (значение), или <em>отклоненным </em>(<em>rejected),</em> вернув причину отказа. В любом из этих случаев вызывается обработчик, прикрепленный к промису методом <code>then</code>. (Если в момент назначения обработчика промис уже исполнен или отклонен, обработчик все равно будет вызван, т.е. асинхронное исполнение промиса и назначение обработчика не будет происходить в «состоянии гонки», как, например, в случае с событиями в DOM.)</p>
<p>Так как методы <code>{{JSxRef("Promise.then", "Promise.prototype.then()")}}</code> и <code>{{JSxRef("Promise.catch", "Promise.prototype.catch()")}}</code> сами возвращают промис, их можно вызывать цепочкой, создавая <em>соединения.</em></p>
<p><img alt="" src="https://mdn.mozillademos.org/files/8633/promises.png" style="height: 297px; width: 801px;"></p>
<div class="blockIndicator note">
<p><strong>Примечание:</strong> говорят, что промис находится в состоянии <em>завершен (settled) </em>когда он или исполнен или отклонен, т.е. в любом состоянии, кроме ожидания (это лишь форма речи, не являющаяся настоящим состоянием промиса). Также можно встретить термин <em>исполин (resolved) </em>— это значит что промис <em>завершен </em>или "заблокирован" в ожидании завершения другого промиса. В статье <a href="https://github.com/domenic/promises-unwrapping/blob/master/docs/states-and-fates.md">состояния и fates</a> приводится более подробное описание терминологии.</p>
</div>
<h2 id="Свойства">Свойства</h2>
<dl>
<dt><code>Promise.length</code></dt>
<dd>Значение свойства всегда равно 1 (количество аргументов конструктора).</dd>
<dt>{{jsxref("Promise.prototype")}}</dt>
<dd>Представляет прототип для конструктора <code>Promise</code>.</dd>
</dl>
<h2 id="Методы">Методы</h2>
<dl>
<dt>{{jsxref("Promise.all", "Promise.all(iterable)")}}</dt>
<dd>Ожидает исполнения всех промисов или отклонения любого из них.</dd>
<dd>Возвращает промис, который исполнится после исполнения всех промисов в <code>iterable</code>. В случае, если любой из промисов будет отклонен, <code>Promise.all</code> будет также отклонен.</dd>
<dt>{{JSxRef("Promise.allSettled", "Promise.allSettled(iterable)")}}</dt>
<dd>Ожидает завершения всех полученных промисов (как исполнения так и отклонения).</dd>
<dd>Возвращает промис, который исполняется когда все полученные промисы завершены (исполнены или отклонены), содержащий массив результатов исполнения полученных промисов.</dd>
<dt>{{jsxref("Promise.race", "Promise.race(iterable)")}}</dt>
<dd>Ожидает исполнения или отклонения любого из полученных промисов.</dd>
<dd>Возвращает промис, который будет исполнен или отклонен с результатом исполнения первого исполненного или отклонённого промиса из .<code>iterable</code>.</dd>
</dl>
<dl>
<dt>{{jsxref("Promise.reject", "Promise.reject(reason)")}}</dt>
<dd>Возвращает промис, отклонённый из-за <code>reason</code>.</dd>
</dl>
<dl>
<dt>{{jsxref("Promise.resolve", "Promise.resolve(value)")}}</dt>
<dd>Возвращает промис, исполненный с результатом <code>value</code>.</dd>
<dd>
<div class="hidden">
<p>Если у <code>value</code> имеется метод <code>then</code>, то возвращаемый промис будет "следовать" продолжению, выступая адаптером его состояния; в противном случае будет возвращен промис в исполненном состоянии. Если вы не уверены, является ли некоторое значение промисом, вы можете обернуть его в {{JSxRef("Promise.resolve", "Promise.resolve(value)")}} и продолжить работу с ним как с промисом.</p>
</div>
</dd>
</dl>
<h2 id="Прототип_Promise">Прототип <code>Promise</code></h2>
<h3 id="Свойства_2">Свойства</h3>
<p>{{page('ru/docs/Web/JavaScript/Reference/Global_Objects/Promise/prototype','Свойства')}}</p>
<h3 id="Методы_2">Методы</h3>
<p>{{page('ru/docs/Web/JavaScript/Reference/Global_Objects/Promise/prototype','Методы')}}</p>
<h2 id="Создание_промиса">Создание промиса</h2>
<p>Объект <code>Promise</code> создается при помощи ключевого слова <code>new</code> и своего конструктора. Конструктор <code>Promise</code> принимает в качестве аргумента функцию, называемую "исполнитель" (<em>executor function</em>). Эта функция должна принимать две функции-колбэка в качестве параметров. Первый из них (<code>resolve</code>) вызывается, когда асинхронная операция завершилась успешно и вернула результат своего исполнения в виде значения. Второй колбэк (<code>reject</code>) вызывается, когда операция не удалась, и возвращает значение, указывающее на причину неудачи, чаще всего объект ошибки.</p>
<pre class="brush: js">const myFirstPromise = new Promise((resolve, reject) => {
// выполняется асинхронная операция, которая в итоге вызовет:
//
// resolve(someValue); // успешное завершение
// или
// reject("failure reason"); // неудача
});</pre>
<p>Чтобы снабдить функцию функционалом обещаний, нужно просто вернуть в ней объект <code>Promise</code>:</p>
<pre class="brush: js">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();
});
}</pre>
<h2 id="Примеры">Примеры</h2>
<h3 id="Простой_пример">Простой пример</h3>
<pre class="brush: html" class="hidden">Создать промис!
</pre>
<pre class="brush: 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);
});</pre>
<h3 id="Продвинутый_пример">Продвинутый пример</h3>
<pre class="brush: html" class="hidden">Создать промис!
</pre>
<div id="log">
<pre class="brush: html"><button id="btn">Создать Promise!</button>
<div id="log"></div></pre>
</div>
<p>Данный небольшой пример показывает механизм работы с <code>Promise</code>. Метод <code>testPromise()</code> вызывается при каждом нажатии на {{HTMLElement("button")}}. При этом создаётся промис, которое успешно выполняется при помощи <code>window.setTimeout</code>, со значением <code>'result'</code> в случайном интервале от 1 до 3-х секунд.</p>
<p>исполнение промиса протоколируется при помощи продолжения <code>p1.then</code>. Это показывает как синхронная часть метода отвязана от асинхронного завершения промиса.</p>
<pre class="brush: js">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 +
') Обещание создано (синхронный код завершён)
');
}
</pre>
<pre class="brush:js" class="hidden">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.";
}
</pre>
<pre class="brush: js">if ("Promise" in window) {
let btn = document.getElementById("btn");
btn.addEventListener("click",testPromise);
} else {
log = document.getElementById('log');
log.innerHTML = "Демонстрация невозможна, поскольку ваш браузер не поддерживает интерфейс <code>Promise<code>.";
}</pre>
<p>Данный пример запускается при нажатии на кнопку. Для этого вам необходим браузер, поддерживающий <code>Promise</code>. При последовательных нажатиях на кнопку с коротким интервалом, вы можете увидеть как различные промиса будут исполнены один за другим.</p>
<h3 id="Загрузка_изображения_при_помощи_XHR">Загрузка изображения при помощи XHR</h3>
<p>Другой простой пример использования <code>Promise</code> и <code><a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a></code> для загрузки изображения доступен в репозитории MDN<a href="https://github.com/mdn/js-examples/tree/master/promises-test">promise-test</a> на GitHub. Вы также можете <a href="https://mdn.github.io/js-examples/promises-test/">посмотреть его в действии</a>. Каждый шаг прокомментирован и вы можете подробно исследовать Promise и XHR.</p>
<h2 id="Спецификации">Спецификации</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Спецификация</th>
<th scope="col">Статус</th>
<th scope="col">Комментарий</th>
</tr>
<tr>
<td><a href="https://github.com/domenic/promises-unwrapping">domenic/promises-unwrapping</a></td>
<td>Черновик</td>
<td>Начало работы над стандартом.</td>
</tr>
<tr>
<td>{{SpecName('ES6', '#sec-promise-objects', 'Promise')}}</td>
<td>{{Spec2('ES6')}}</td>
<td>Изначальное определение в стандарте ECMA.</td>
</tr>
</tbody>
</table>
<h2 id="Совместимость_с_браузерами">Совместимость с браузерами</h2>
<p>{{Compat("javascript.builtins.Promise")}}</p>
<h2 id="Смотрите_также">Смотрите также</h2>
<ul>
<li><a href="http://promisesaplus.com/">Спецификация Promises/A+</a></li>
<li><a href="http://www.html5rocks.com/en/tutorials/es6/promises/">Jake Archibald: JavaScript Promises: There and Back Again</a></li>
<li><a href="http://de.slideshare.net/domenicdenicola/callbacks-promises-and-coroutines-oh-my-the-evolution-of-asynchronicity-in-javascript">Domenic Denicola: Callbacks, Promises, and Coroutines – Asynchronous Programming Pattern in JavaScript</a></li>
<li><a href="http://www.mattgreer.org/articles/promises-in-wicked-detail/">Matt Greer: JavaScript Promises ... In Wicked Detail</a></li>
<li><a href="https://www.promisejs.org/">Forbes Lindesay: promisejs.org</a></li>
<li><a href="http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html">Nolan Lawson: We have a problem with promises — Common mistakes with promises</a></li>
<li><a href="https://github.com/jakearchibald/es6-promise/">Promise polyfill</a></li>
<li><a href="https://www.udacity.com/course/javascript-promises--ud898">Udacity: JavaScript Promises</a></li>
</ul>
|