aboutsummaryrefslogtreecommitdiff
path: root/files/uk/web/javascript/guide/using_promises/index.html
blob: d3b986e51a2e730f45166a24df217e3e5c4fa3f9 (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
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
---
title: Використання промісів
slug: Web/JavaScript/Guide/Using_promises
tags:
  - JavaScript
  - Promise
  - Посібник
  - Проміс
  - асинхронний
translation_of: Web/JavaScript/Guide/Using_promises
---
<div>{{jsSidebar("JavaScript Guide")}}</div>

<div>{{PreviousNext("Web/JavaScript/Guide/Dokladno_pro_Objectnu_Model", "Web/JavaScript/Guide/Iterators_and_Generators")}}</div>

<p>{{jsxref("Promise")}} (з англ. - "обіцянка", далі - "проміс") - це об'єкт, що відображає кінцеве завершення або невдачу асинхронної операції. Оскільки більшість людей є споживачами раніше створенних промісів, цей посібник спочатку пояснить споживання повернених промісів, а далі пояснить, як їх створювати.</p>

<p>Проміс, по суті, є поверненим об'єктом, до якого ви прикріплюєте функції зворотного виклику, замість того, щоб передавати їх у функцію.</p>

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

<p>Ось код, який використовує <code>createAudioFileAsync()</code>:</p>

<pre class="brush: js line-numbers  language-js notranslate">function successCallback(result) {
  console.log("Аудіофайл створений за адресою: " + result);
}

function failureCallback(error) {
  console.log("Під час створення аудіофайлу виникла помилка: " + error);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
</pre>

<p>Замість цього, сучасні функції повертають проміс, до якого ви можете приєднати функції зворотного виклику:</p>

<p>Якщо переписати функцію <code>createAudioFileAsync()</code>, щоб вона повертала проміс, її використання буде ось таким простим:</p>

<pre class="brush: js notranslate">createAudioFileAsync(audioSettings).then(successCallback, failureCallback);</pre>

<p>Це скорочений запис для:</p>

<pre class="brush: js notranslate">const promise = createAudioFileAsync(audioSettings);
promise.then(successCallback, failureCallback);</pre>

<p>Ми називаємо це <em>асинхронним викликом функції</em>.  Ця конвенція має декілька переваг. Ми дослідимо кожну з них.</p>

<h2 id="Гарантії">Гарантії</h2>

<p>На відміну від старомодних колбеків, проміс постачається з певними гарантіями:</p>

<ul>
 <li>Функції зворотного виклику ніколи не будуть викликані до <a href="/uk/docs/Web/JavaScript/EventLoop">завершення поточного виконання</a> циклу подій JavaScript.</li>
 <li>Функції зворотного виклику, додані за допомогою <code><a href="/uk/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code>, навіть <em>після</em> успіху або невдачі асинхронної операції, будуть викликані, як наведено вище.</li>
 <li>Можна додати більше одного зворотного виклику, викликавши метод <code><a href="/uk/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> декілька разів. Кожен зворотний виклик виконується один за одним, у тому порядку, в якому вони були додані.</li>
</ul>

<p>Однією з величезних переваг промісів є <strong>ланцюгування</strong>.</p>

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

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

<p>Ось вам магія: функція <code>then()</code> повертає <strong>новий проміс</strong>, що відрізняється від оригіналу:</p>

<pre class="brush: js notranslate">const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
</pre>

<p>або</p>

<pre class="brush: js notranslate">const promise2 = doSomething().then(successCallback, failureCallback);
</pre>

<p>Цей другий проміс (<code>promise2</code>) представляє собою завершення не тільки <code>doSomething()</code>, але й <code>successCallback</code> або <code>failureCallback</code>, які ви передали, вони, в свою чергу, можуть бути іншими асинхронними функціями, що повертають проміс. В цьому випадку будь-які функції зворотного виклику, додані до <code>promise2</code>, стають в чергу за промісом, що повертається <code>successCallback</code> чи <code>failureCallback</code>.</p>

<p>По суті, кожен проміс відображає завершення іншого асинхроннго кроку в ланцюжку.</p>

<p>В старі часи виконання декількох асинхронних операцій підряд призвело б до класичної піраміди смерті з колбеків:</p>

<pre class="brush: js notranslate">doSomething(function(result) {
  doSomethingElse(result, function(newResult) {
    doThirdThing(newResult, function(finalResult) {
      console.log('Ось фінальний результат: ' + finalResult);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
</pre>

<p>З сучасними функціями замість цього ми приєднуємо наші функції зворотного виклику до промісів, що повертаються, формуючи ланцюжок промісів.</p>

<pre class="brush: js notranslate">doSomething().then(function(result) {
  return doSomethingElse(result);
})
.then(function(newResult) {
  return doThirdThing(newResult);
})
.then(function(finalResult) {
  console.log('Ось фінальний результат: ' + finalResult);
})
.catch(failureCallback);
</pre>

<p>Аргументи до <code>then</code> є необов'язковими, а <code>catch(failureCallback)</code> - це скорочений запис для  <code>then(null, failureCallback)</code>. Ви можете побачити це, виражене за допомогою <a href="/uk/docs/Web/JavaScript/Reference/Functions/Стрілкові_функції">стрілкових функцій</a>:</p>

<pre class="brush: js notranslate">doSomething()
.then(result =&gt; doSomethingElse(result))
.then(newResult =&gt; doThirdThing(newResult))
.then(finalResult =&gt; {
  console.log(`Ось фінальний результат: ${finalResult}`);
})
.catch(failureCallback);
</pre>

<p><strong>Важливо</strong>: Завжди повертайте результати, інакше функції зворотного виклику не перехоплять результат попереднього проміса (у стрілкових функціях <code>() =&gt; x</code> є скороченим записом для <code>() =&gt; { return x; }</code>).</p>

<h3 id="Ланцюгування_після_catch">Ланцюгування після catch</h3>

<p>Ланцюгувати <em>після </em>невдачі можливо, наприклад, <code>catch</code> є корисним у разі виконання нових операцій навіть після того, як операція у ланцюжку завершилась неуспішно. Дивіться наступний приклад:</p>

<pre class="brush: js notranslate">new Promise((resolve, reject) =&gt; {
    console.log('Початковий');

    resolve();
})
.then(() =&gt; {
    throw new Error('Щось пішло не так');

    console.log('Зробити це');
})
.catch(() =&gt; {
    console.log('Зробити те');
})
.then(() =&gt; {
    console.log('Зробити це, що б не відбувалось раніше');
});

</pre>

<p>Це виведе наступний текст:</p>

<pre class="notranslate">Початковий
Зробити те
Зробити це, що б не відбувалось раніше
</pre>

<p><strong>Зауважте:</strong> Текст "Зробити це" не був виведений, тому що помилка "Щось пішло не так" спричинила відхилення.</p>

<h2 id="Спливання_помилок">Спливання помилок</h2>

<p>Ви, можливо, пригадуєте, що тричі бачили <code>failureCallback</code> раніше, у піраміді смерті, у порівнянні з лише одним викликом наприкінці ланцюжку промісів.</p>

<pre class="brush: js notranslate">doSomething()
.then(result =&gt; doSomethingElse(value))
.then(newResult =&gt; doThirdThing(newResult))
.then(finalResult =&gt; console.log(`Ось фінальний результат: ${finalResult}`))
.catch(failureCallback);
</pre>

<p>Якщо виникає виняток, переглядач передивляється ланцюжок у пошуках обробників <code>catch</code> або <code>onRejected</code>. Це дуже схоже на модель того, як працює синхронний код:</p>

<pre class="brush: js notranslate">try {
  let result = syncDoSomething();
  let newResult = syncDoSomethingElse(result);
  let finalResult = syncDoThirdThing(newResult);
  console.log(`Ось фінальний результат: ${finalResult}`);
} catch(error) {
  failureCallback(error);
}
</pre>

<p>Ця симетрія з асинхронним кодом сягає кульмінації в синтаксичному цукрі <a href="/uk/docs/Web/JavaScript/Reference/Statements/async_function"><code>async</code>/<code>await</code></a> в ECMAScript 2017:</p>

<pre class="brush: js notranslate">async function foo() {
  try {
    let result = await doSomething();
    let newResult = await doSomethingElse(result);
    let finalResult = await doThirdThing(newResult);
    console.log(`Ось фінальний результат: ${finalResult}`);
  } catch(error) {
    failureCallback(error);
  }
}
</pre>

<p>Він будується на промісах, наприклад, <code>doSomething()</code> - це та сама функція, що й раніше. Ви можете прочитати більше про синтаксис <a href="https://developers.google.com/web/fundamentals/primers/async-functions">тут</a>.</p>

<p>Проміси виправляють фундаментальну хибу з пірамідою смерті, перехоплюючи всі помилки, навіть викинуті винятки та помилки программування. Це критично важливо для функціональної композиції асинхронних операцій.</p>

<h2 id="Події_відхилення_промісів">Події відхилення промісів</h2>

<p>Коли проміс відхиляється, одна з двох подій надсилається у глобальну область видимості (загалом, це або <a href="/uk/docs/Web/API/Window"><code>window</code></a>, або, при використанні у веб-виконавці, це <a href="/uk/docs/Web/API/Worker"><code>Worker</code></a> або інший інтерфейс на базі виконавців). Ці дві події наступні:</p>

<dl>
 <dt><a href="/uk/docs/Web/API/Window/rejectionhandled_event" title="Подія rejectionhandled надсилається у глобальну область видимості скрипта (зазвичай, window, але також і Worker), коли об'єкт JavaScript Promise відхиляється, але після того, як відхилення було оброблене."><code>rejectionhandled</code></a></dt>
 <dd>Надсилається, коли проміс відхиляється, після того, як відхилення було оброблене функцією виконавця <code>reject</code>.</dd>
 <dt><a href="/uk/docs/Web/API/Window/unhandledrejection_event" title="Подія unhandledrejection надсилається у глобальну область видимості скрипта, коли об'єкт JavaScript Promise, який не має обробника відхилення, відхиляється; зазвичай, це window, але також може бути Worker."><code>unhandledrejection</code></a></dt>
 <dd>Надсилається, коли проміс відхиляється, але немає доступного обробника відхилення.</dd>
</dl>

<p>У обох випадках подія (типу <a href="/uk/docs/Web/API/PromiseRejectionEvent" title="Інтерфейс PromiseRejectionEvent відображає події, які надсилаються у глобальний контекст скрипта, коли об'єкти JavaScript Promise відхиляються."><code>PromiseRejectionEvent</code></a>) має в якості полів властивість <a href="/uk/docs/Web/API/PromiseRejectionEvent/promise"><code>promise</code></a>, яка вказує відхилений проміс, та властивість <a href="/uk/docs/Web/API/PromiseRejectionEvent/reason"><code>reason</code></a>, яка передає надану причину відхилення проміса.</p>

<p>Це робить можливою резервну обробку помилок для промісів, а також допомагає відлагоджувати проблеми в управлінні промісами. Ці обробники є глобальними за контекстом, тому усі помилки потраплятимуть в однакові обробники подій, незалежно від джерела.</p>

<p>Один випадок особливої корисності: при написанні коду для {{Glossary("Node.js")}}, зазвичай, модулі, які ви включаєте у свій проект, можуть мати необроблені відхилені проміси. Вони виводяться у консоль середовищем виконання Node. Ви можете перехопити їх для аналізу та обробити у своєму коді — або просто уникнути захаращення ними виводу даних — додавши обробник події <a href="/uk/docs/Web/API/Window/unhandledrejection_event"><code>unhandledrejection</code></a>, ось так:</p>

<pre class="brush: js notranslate">window.addEventListener("unhandledrejection", event =&gt; {
  /* Ви можете почати тут, додавши код, щоб дослідити
     вказаний проміс через event.promise та причину у
     event.reason */

  event.preventDefault();
}, false);</pre>

<p>Викликавши метод події <a href="/uk/docs/Web/API/Event/preventDefault" title="Метод інтерфейсу Event preventDefault() каже програмному агенту, що, якщо подія не була явно оброблена, її дія за замовчуванням не має виконуватись."><code>preventDefault()</code></a>, ви кажете середовищу виконання JavaScript не виконувати дію за замовчуванням, коли відхилений проміс лишається необробленим. Ця дія зазвичай містить виведення помилки у консоль, а це якраз випадок для Node.</p>

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

<h2 id="Створення_промісу_на_основі_старого_API_зі_зворотним_викликом">Створення промісу на основі старого API зі зворотним викликом</h2>

<p>{{jsxref("Promise","Проміс")}} може бути створенний з нуля за допогою свого конструктора. Це необхідно лише для обгортки старих API.</p>

<p>В ідеальному світі всі асинхронні функції повертали б проміси. На жаль, деякі API досі очікують старомодну передачу функцій зворотного виклику для успіху та/або невдачі. Найбільш очевидним прикладом є функція {{domxref("WindowTimers.setTimeout", "setTimeout()")}} :</p>

<pre class="brush: js notranslate">setTimeout(() =&gt; saySomething("Пройшло 10 секунд"), 10000);
</pre>

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

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

<pre class="brush: js notranslate">const wait = ms =&gt; new Promise(resolve =&gt; setTimeout(resolve, ms));

wait(10000).then(() =&gt; saySomething("10 секунд")).catch(failureCallback);
</pre>

<p>По суті, конструктор промісу приймає функцію виконання, яка дозволяє вирішити або відхилити проміс вручну. Оскільки <code>setTimeout</code>, насправді, ніколи не завершується невдало, ми пропускаємо функцію відхилення в цьому випадку.</p>

<h2 id="Композиція">Композиція</h2>

<p>Методи {{jsxref("Promise.resolve()")}} та {{jsxref("Promise.відхилено", "Promise.reject()")}} є скороченими записами для створення вручну вже вирішених або відхилених промісів відповідно. Інколи це може бути корисно.</p>

<p>Методи {{jsxref("Promise.all()")}} та {{jsxref("Promise.race()")}} є двома інструментами композиції для паралельного виконання асинхронних операції.</p>

<p>Ми можемо почати операції паралельно та чекати, доки вони усі не завершаться ось так:</p>

<pre class="brush: js notranslate">Promise.all([func1(), func2(), func3()])
.then(([result1, result2, result3]) =&gt; { /* використати result1, result2 та result3 */ });</pre>

<p>Послідовна композиція можлива з використанням певного розумного JavaScript:</p>

<pre class="brush: js notranslate">[func1, func2, func3].reduce((p, f) =&gt; p.then(f), Promise.resolve())
.then(result3 =&gt; { /* використати result3 */ });</pre>

<p>По суті, ми зменшуємо масив асинхронних функцій до ланцюжка промісів, еквівалентного: <code>Promise.resolve().then(func1).then(func2).then(func3);</code></p>

<p>Це можна перетворити на композиційну функцію багаторазового використання, що є типовим у функціональному програмуванні:</p>

<pre class="brush: js notranslate">const applyAsync = (acc,val) =&gt; acc.then(val);
const composeAsync = (...funcs) =&gt; x =&gt; funcs.reduce(applyAsync, Promise.resolve(x));</pre>

<p>Функція <code>composeAsync()</code> прийме будь-яку кількість функцій в якості аргументів і поверне нову функцію, яка приймає початкове значення, що має пройти крізь конвеєр композиції:</p>

<pre class="brush: js notranslate">const transformData = composeAsync(func1, func2, func3);
const result3 = transformData(data);
</pre>

<p>В ECMAScript 2017 послідовну композицію можна виконати простіше, за допомогою async/await:</p>

<pre class="brush: js notranslate">let result;
for (const f of [func1, func2, func3]) {
  result = await f(result);
}
/* використати останній результат (тобто, result3) */</pre>

<h2 id="Хронометраж">Хронометраж</h2>

<p>Щоб уникнути сюрпризів, функції, передані до <code>then()</code>, ніколи не викликатимуться синхронно, навіть для вже вирішеного проміса:</p>

<pre class="brush: js notranslate">Promise.resolve().then(() =&gt; console.log(2));
console.log(1); // 1, 2
</pre>

<p>Замість негайного виконання, передані функції ставляться у чергу мікрозадач. Це означає, що вони виконуються пізніше, коли черга стає порожньою в кінці поточного виконання циклу подій JavaScript, тобто, досить скоро:</p>

<pre class="brush: js notranslate">const wait = ms =&gt; new Promise(resolve =&gt; setTimeout(resolve, ms));

wait().then(() =&gt; console.log(4));
Promise.resolve().then(() =&gt; console.log(2)).then(() =&gt; console.log(3));
console.log(1); // 1, 2, 3, 4
</pre>

<h2 id="Вкладеність">Вкладеність</h2>

<p>Прості ланцюжки промісів найкраще тримати рівними, без вкладень, оскільки вкладення можуть бути результатом недбалої композиції. Дивіться <a href="#Типові_помилки">типові помилки</a>.</p>

<p>Вкладеність є контролюючою структурою для обмеження області видимості блоків <code>catch</code>. Зокрема, вкладений <code>catch</code> перехоплює лише помилки своєї області видимості та нижче, але не ті помилки, що знаходяться вище у ланцюжку поза вкладеною областю видимості. При правильному використанні це надає більшу точність у виявленні помилок:</p>

<pre class="brush: js notranslate">doSomethingCritical()
.then(result =&gt; doSomethingOptional(result)
  .then(optionalResult =&gt; doSomethingExtraNice(optionalResult))
  .catch(e =&gt; {})) // Ігнорувати, якщо не працює щось другорядне; продовжити.
.then(() =&gt; moreCriticalStuff())
.catch(e =&gt; console.error("Критична помилка: " + e.message));</pre>

<p>Зауважте, що необов'язкові кроки тут вкладені, не для відступів, але для передбачливого розташування зовнішніх дужок <code>(</code> та <code>)</code> навколо.</p>

<p>Внутрішній нейтралізуючий блок <code>catch</code> перехоплює помилки тільки від <code>doSomethingOptional()</code> та <code>doSomethingExtraNice()</code>, після чого виконання коду продовжується у <code>moreCriticalStuff()</code>. Що важливо, якщо функція <code>doSomethingCritical()</code> завершується невдало, її помилка перехоплюється тільки кінцевим (зовнішнім) блоком <code>catch</code>.</p>

<h2 id="Типові_помилки">Типові помилки</h2>

<p>Ось деякі типові помилки, яких варто остерігатися при складанні ланцюжків промісів. Декілька з цих помилок проявляються у наступному прикладі:</p>

<pre class="brush: js example-bad notranslate">// Поганий приклад! Помічено 3 помилки!

doSomething().then(function(result) {
  doSomethingElse(result) // Забули повернути проміс з внутрішнього ланцюжка + непотрібне вкладення
  .then(newResult =&gt; doThirdThing(newResult));
}).then(() =&gt; doFourthThing());
// Забули завершити ланцюжок блоком catch!
&lt;/pre&gt;</pre>

<p>Перша помилка - не завершувати ланцюжки як слід. Це відбувається, коли ми створюємо новий проміс, але забуваємо його повернути. Як наслідок, ланцюг переривається, чи, скоріше, ми отримуємо два конкуруючі ланцюжки. Це означає, що <code>doFourthThing()</code> не чекатиме на завершення <code>doSomethingElse()</code> чи <code>doThirdThing()</code> і запуститься паралельно з ними, скоріше за все, ненавмисно. В окремих ланцюжках також окремо обробляються помилки, що призводить до неперехоплених помилок.</p>

<p>Друга помилка - непотрібна вкладеність, що уможливлює першу помилку. Вкладеність також обмежує область видимості внутрішніх обробників помилок, а це — якщо зроблене ненавмисно — може призвести до неперехоплених помилок. Варіантом цього є <a href="https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it">антишаблон конструювання промісів</a>, який поєднує вкладення з надлишковим використанням конструктора промісів для загортання коду, який вже використовує проміси.</p>

<p>Третя помилка - забувати завершувати ланцюжки блоком <code>catch</code>. Незавершені ланцюжки промісів призводять до неперехоплених відхилень промісів у більшості переглядачів.</p>

<p>Гарний практичний підхід - завжди або повертати, або завершувати ланцюжки промісів, і, як тільки ви отримуєте новий проміс, повертати його негайно, щоб вирівняти ланцюжок:</p>

<pre class="brush: js example-good notranslate">doSomething()
.then(function(result) {
  return doSomethingElse(result);
})
.then(newResult =&gt; doThirdThing(newResult))
.then(() =&gt; doFourthThing())
.catch(error =&gt; console.error(error));</pre>

<p>Зауважте, що <code>() =&gt; x</code> є скороченням для <code>() =&gt; { return x; }</code>.</p>

<p>Тепер ми маємо єдиний, детермінований ланцюжок з правильною обробкою помилок.</p>

<p>Використання <a href="/uk/docs/Web/JavaScript/Reference/Statements/async_function"><code>async</code>/<code>await</code></a> вирішує більшість, якщо не всі ці проблеми — натомість, найпоширенішою помилкою при використанні цього синтаксису є забуте ключове слово <a href="/uk/docs/Web/JavaScript/Reference/Statements/async_function"><code>await</code></a>.</p>

<h2 id="Коли_зустрічаються_задачі_та_проміси">Коли зустрічаються задачі та проміси</h2>

<p>Якщо ви стикаєтеся з ситуаціями, коли у вас є проміси та задачі (такі, як події або зворотні виклики), які запускаються у непередбачуваному порядку, можливо, вам буде корисно скористатись мікрозадачами, щоб перевірити статус або збалансувати проміси, коли створення промісів залежить від певних умов.</p>

<p>Якщо ви вважаєте, що мікрозадачі могли б вирішити цю проблему, дивіться <a href="/uk/docs/Web/API/HTML_DOM_API/Microtask_guide">посібник з мікрозадач</a>, щоб дізнатись, як використовувати метод <code><a href="/uk/docs/Web/API/WindowOrWorkerGlobalScope/queueMicrotask" title="The queueMicrotask() method, which is exposed on the Window or Worker interface, queues a microtask to be executed at a safe time prior to control returning to the browser's event loop.">queueMicrotask()</a></code>, щоб поставити функцію у чергу як мікрозадачу.</p>

<h2 id="Дивіться_також">Дивіться також</h2>

<ul>
 <li>{{jsxref("Promise.then()")}}</li>
 <li><a href="/uk/docs/Web/JavaScript/Reference/Statements/async_function"><code>async</code>/<code>await</code></a> </li>
 <li><a href="http://promisesaplus.com/">Promises/A+ specification</a></li>
 <li><a href="https://medium.com/@ramsunvtech/promises-of-promise-part-1-53f769245a53">Venkatraman.R - JS Promise (Part 1, Basics)</a></li>
 <li><a href="https://medium.com/@ramsunvtech/js-promise-part-2-q-js-when-js-and-rsvp-js-af596232525c#.dzlqh6ski">Venkatraman.R - JS Promise (Part 2 - Using Q.js, When.js and RSVP.js)</a></li>
 <li><a href="https://tech.io/playgrounds/11107/tools-for-promises-unittesting/introduction">Venkatraman.R - Tools for Promises Unit Testing</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>
</ul>

<p>{{PreviousNext("Web/JavaScript/Guide/Dokladno_pro_Objectnu_Model", "Web/JavaScript/Guide/Iterators_and_Generators")}}</p>