aboutsummaryrefslogtreecommitdiff
path: root/files/uk/web/javascript/reference/global_objects/promise/then/index.html
blob: 8cbcc884fcda6561ae5a340571b7d28ad8ebf189 (plain)
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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
---
title: Promise.prototype.then()
slug: Web/JavaScript/Reference/Global_Objects/Promise/then
tags:
  - ECMAScript 2015
  - JavaScript
  - Promise
  - метод
translation_of: Web/JavaScript/Reference/Global_Objects/Promise/then
---
<div>{{JSRef}}</div>

<p>Метод <code><strong>then()</strong></code> вертає об'єкт {{jsxref("Promise")}}. Він приймає два аргументи: функції зворотного виклику для випадків успішного та неуспішного проміса.</p>

<div>{{EmbedInteractiveExample("pages/js/promise-then.html")}}</div>

<p class="hidden">The source for this interactive demo is stored in a GitHub repository. If you'd like to contribute to the interactive demo project, please clone <a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> and send us a pull request.</p>

<div class="note">
<p>Якщо один чи обидва аргументи пропущені, або надані не функції, тоді <code>then</code> не матиме обробників, але не згенерує помилок. Якщо <code>Promise</code>, на якому викликається <code>then</code>, приймає стан (<code>виконання</code> або <code>відхилення</code>), для якого <code>then</code> не має обробника, новий <code>Promise</code> створюється без додаткових обробників, просто приймаючи кінцевий стан оригінального проміса, на якому було викликано <code>then</code>.</p>
</div>

<h2 id="Синтаксис">Синтаксис</h2>

<pre class="syntaxbox"><var>p.then(onFulfilled[, onRejected])</var>;

p.then(value =&gt; {
  // виконання
}, reason =&gt; {
  // відхилення
});
</pre>

<h3 id="Параметри">Параметри</h3>

<dl>
 <dt><code>onFulfilled</code> {{optional_inline}}</dt>
 <dd>{{jsxref("Function","Функція")}}, що викликається, якщо <code>Promise</code> виконано. Ця функція має один аргумент, <code>значення виконання</code>. Якщо це не функція, вона внутрішньо замінюється на функцію "Identity" (вона повертає отриманий аргумент).</dd>
 <dt><code>onRejected</code> {{optional_inline}}</dt>
 <dd>{{jsxref("Function","Функція")}}, що викликається, якщо <code>Promise</code> відхилено. Ця функція має один аргумент, <code>причина відхилення</code>. Якщо це не функція, вона внутрішньо замінюється на функцію "Thrower" (вона викидає помилку, яку отримала в якості аргумента).</dd>
</dl>

<h3 id="Значення_що_повертається">Значення, що повертається</h3>

<p>Як тільки {{jsxref("Promise","проміс")}} був виконаний або відхилений, відповідна функція-обробник (<code style="font-style: normal; font-weight: normal;">onFulfilled</code> або <code style="font-style: normal; font-weight: normal;">onRejected</code>) буде викликана <strong>асинхронно</strong> (запланована у активному циклі потоку). Поведінка функції-обробника відповідає спеціальному набору правил. Якщо функція-обробник:</p>

<ul>
 <li>вертає значення, проміс, повернений <code>then</code>, вирішується з поверненим значенням в якості його значення.</li>
 <li>не вертає нічого, проміс, повернений <code>then</code>, вирішується зі значенням <code>undefined</code>.</li>
 <li>викидає помилку, проміс, повернений <code>then</code>, відхиляється з викинутою помилкою в якості значення.</li>
 <li>вертає вже виконаний проміс, то проміс, повернений <code>then</code>, виконується зі значенням цього проміса в якості свого значення.</li>
 <li>вертає вже відхилений проміс, то проміс, повернений <code>then</code>, відхиляється зі значенням цього проміса в якості свого значення.</li>
 <li>вертає інший проміс <strong>у стані очікування</strong>, вирішення/відхилення проміса, поверненого <code>then</code>, буде результатом вирішення/відхилення проміса, поверненого обробником. Також, вирішене значення проміса, поверненого <code>then</code>, буде тим самим, що й вирішене значення проміса, поверненого обробником.</li>
</ul>

<p>Наступний приклад демонструє асинхронність методу <code>then</code>.</p>

<pre class="brush: js">// при використанні вирішеного проміса блок 'then' буде негайно запущений,
// але його обробники запустяться асинхронно, як демонструє console.log
const resolvedProm = Promise.resolve(33);

let thenProm = resolvedProm.then(value =&gt; {
    console.log("Це запускається після завершення головного стеку. Отримане й повернене значення: " + value);
    return value;
});
// негайне логування значення thenProm
console.log(thenProm);

// використовуючи setTimeout, ми можемо відкласти виконання функції, поки стек не стане порожнім
setTimeout(() =&gt; {
    console.log(thenProm);
});


// порядок логування:
// Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
// "Це запускається після завершення головного стеку. Отримане й повернене значення: 33"
// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 33}</pre>

<h2 id="Опис">Опис</h2>

<p>Оскільки методи <code>then</code> та {{jsxref("Promise.prototype.catch()")}} вертають проміси, їх <a href="/uk/docs/Web/JavaScript/Guide/Using_promises#Chaining">можна поєднувати в ланцюги</a> — ця операція зветься <em>композицією</em>.</p>

<h2 id="Приклади">Приклади</h2>

<h3 id="Використання_метода_then">Використання метода <code>then</code></h3>

<pre class="brush: js">var p1 = new Promise((resolve, reject) =&gt; {
  resolve('Успіх!');
  // або
  // reject(new Error("Помилка!"));
});

p1.then(value =&gt; {
  console.log(value); // Успіх!
}, reason =&gt; {
  console.error(reason); // Помилка!
});
</pre>

<h3 id="Ланцюгування">Ланцюгування</h3>

<p>Метод <code>then</code> вертає об'єкт <code>Promise</code>, що дозволяє використовувати ланцюгування.</p>

<p>Якщо функція, передана у <code>then</code> в якості обробника, вертає об'єкт <code>Promise</code>, аналогічний об'єкт <code>Promise</code> буде переданий у наступний <code>then</code> ланцюга методів. Наведений нижче фрагмент імітує асинхронний код функцією <code>setTimeout</code></p>

<pre class="brush: js">Promise.resolve('ква')
  // 1. Отримати "ква", приєднати "драт" та вирішити це для наступного then
  .then(function(string) {
    return new Promise(function(resolve, reject) {
      setTimeout(function() {
        string += 'драт';
        resolve(string);
      }, 1);
    });
  })
  // 2. отримати "квадрат", призначити функцію зворотного виклику для обробки цього рядка
  // та вивести його на консоль, але не раніше повернення необробленого рядка
  // string у наступний then
  .then(function(string) {
    setTimeout(function() {
      string += 'ура';
      console.log(string);
    }, 1)
    return string;
  })
  // 3. вивести допоміжні повідомлення щодо того, як виконується код в цьому розділі,
  // раніше, ніж рядок string буде оброблений імітованим асинхронним кодом у
  // попередньому блоці then.
  .then(function(string) {
    console.log("Останній Then:  йой... ми не створили та не повернули екземпляр проміса " +
                "у попередньому then, тому послідовність може бути трохи " +
                "несподіваною");

    // Зауважте, що `string` не матиме частини 'ура' в цій точці. Це тому,
    // що ми імітували його асинхронне виконання за допомогою функції setTimeout
    console.log(string);
  });

// порядок виведення:
// Останній Then: йой... ми не створили та не повернули екземпляр проміса у попередньому then, тому послідовність може бути трохи несподіваною
// квадрат
// квадратура</pre>

<p>Коли значення просто повертається з обробника <code>then</code>, він поверне <code>Promise.resolve(&lt;значення, повернене обробником, що викликався&gt;)</code>.</p>

<pre class="brush: js">var p2 = new Promise(function(resolve, reject) {
  resolve(1);
});

p2.then(function(value) {
  console.log(value); // 1
  return value + 1;
}).then(function(value) {
  console.log(value + ' - Синхронне значення працює');
});

p2.then(function(value) {
  console.log(value); // 1
});
</pre>

<p>Виклик <code>then</code> поверне відхилений проміс, якщо функція викидає помилку або повертає відхилений проміс.</p>

<pre class="brush: js">Promise.resolve()
  .then(() =&gt; {
    // Змушує .then() повернути відхилений проміс
    throw new Error('О, ні!');
  })
  .then(() =&gt; {
    console.log('Не викликається.');
  }, error =&gt; {
    console.error('Викликано функцію onRejected: ' + error.message);
  });</pre>

<p>У всіх інших випадках повертається вирішений об'єкт Promise. У наступному прикладі перший <code>then()</code> поверне значення <code>42</code>, загорнуте у вирішений проміс, незважаючи на те, що попередній проміс ланцюжка був відхилений.</p>

<pre class="brush: js">Promise.reject()
  .then(() =&gt; 99, () =&gt; 42) // onRejected вертає 42, обгорнуте у вирішений Promise
  .then(solution =&gt; console.log('Вирішений зі значенням ' + solution)); // Вирішений зі значенням 42</pre>

<p>На практиці часто бажано перехоплювати відхилені проміси, як продемонстровано нижче, а не використовувати синтаксис <code>then</code> для двох випадків.</p>

<pre class="brush: js">Promise.resolve()
  .then(() =&gt; {
    // Змушує .then() повернути відхилений проміс
    throw new Error('О, ні!');
  })
  .catch(error =&gt; {
    console.error('Викликано функцію onRejected: ' + error.message);
  })
  .then(() =&gt; {
    console.log("Мене завжди викликають, навіть якщо проміс попереднього then відхилено");
  });</pre>

<p>Ви також можете використати ланцюгування, щоб реалізувати функцію з API на промісах, на основі іншої такої функції.</p>

<pre class="brush: js">function fetch_current_data() {
  // API <a href="/uk/docs/Web/API/GlobalFetch/fetch">fetch</a>() вертає проміс. Ця функція
  // створює схожий API, крім того, що над значенням
  // виконанного проміса цієї функції виконується
  // більше дій.
  return fetch('current-data.json').then(response =&gt; {
    if (response.headers.get('content-type') != 'application/json') {
      throw new TypeError();
    }
    var j = response.json();
    // можливо, зробити щось із j
    return j; // значення виконання, що надається користувачу
              // fetch_current_data().then()
  });
}
</pre>

<p>Якщо <code>onFulfilled</code> вертає проміс, повернене значення <code>then</code> буде вирішене чи відхилене промісом.</p>

<pre class="brush: js">function resolveLater(resolve, reject) {
  setTimeout(function() {
    resolve(10);
  }, 1000);
}
function rejectLater(resolve, reject) {
  setTimeout(function() {
    reject(new Error('Помилка'));
  }, 1000);
}

var p1 = Promise.resolve('ква');
var p2 = p1.then(function() {
  // Повернути тут проміс, який буде вирішений зі значенням 10 через 1 секунду
  return new Promise(resolveLater);
});
p2.then(function(v) {
  console.log('вирішений', v);  // "вирішений", 10
}, function(e) {
  // не викликається
  console.error('відхилений', e);
});

var p3 = p1.then(function() {
  // Повернути тут проміс, що відхилятиметься з помилкою 'Помилка' через 1 секунду
  return new Promise(rejectLater);
});
p3.then(function(v) {
  // не викликається
  console.log('вирішений', v);
}, function(e) {
  console.error('відхилений', e); // "відхилений", 'Помилка'
});
</pre>

<h3 id="Поліфіл_у_стилі_window.setImmediate_на_основі_промісів">Поліфіл у стилі <a href="/uk/docs/Web/API/Window/setImmediate" title="Цей метод використовується для розбиття довгих у виконанні операцій та запуску функції зворотного виклику негайно після того, як переглядач завершив інші операції, такі, як події та оновлення відображення">window.setImmediate</a> на основі промісів</h3>

<p>Використання методу {{jsxref("Function.prototype.bind()")}} <code>Reflect.apply</code> ({{jsxref("Reflect.apply()")}}) для створення функції (що не скасовується) у стилі setImmediate.</p>

<pre class="brush: js">const nextTick = (() =&gt; {
  const noop = () =&gt; {}; // буквально
  const nextTickPromise = () =&gt; Promise.resolve().then(noop);

  const rfab = Reflect.apply.bind; // (thisArg, fn, thisArg, [...args])
  const nextTick = (fn, ...args) =&gt; (
    fn !== undefined
    ? Promise.resolve(args).then(rfab(null, fn, null))
    : nextTickPromise(),
    undefined
  );
  nextTick.ntp = nextTickPromise;

  return nextTick;
})();
</pre>

<h2 id="Специфікації">Специфікації</h2>

<table class="standard-table">
 <tbody>
  <tr>
   <th scope="col">Специфікація</th>
  </tr>
  <tr>
   <td>{{SpecName('ESDraft', '#sec-promise.prototype.then', 'Promise.prototype.then')}}</td>
  </tr>
 </tbody>
</table>

<h2 id="Сумісність_з_веб-переглядачами">Сумісність з веб-переглядачами</h2>

<p class="hidden">To contribute to this compatibility data, please write a pull request against this repository: <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a>.</p>

<p>{{Compat("javascript.builtins.Promise.then")}}</p>

<h2 id="Див._також">Див. також</h2>

<ul>
 <li>{{jsxref("Promise")}}</li>
 <li>{{jsxref("Promise.prototype.catch()")}}</li>
</ul>