aboutsummaryrefslogtreecommitdiff
path: root/files/uk/web/javascript/reference/statements/async_function/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'files/uk/web/javascript/reference/statements/async_function/index.html')
-rw-r--r--files/uk/web/javascript/reference/statements/async_function/index.html272
1 files changed, 272 insertions, 0 deletions
diff --git a/files/uk/web/javascript/reference/statements/async_function/index.html b/files/uk/web/javascript/reference/statements/async_function/index.html
new file mode 100644
index 0000000000..da4ac5f24a
--- /dev/null
+++ b/files/uk/web/javascript/reference/statements/async_function/index.html
@@ -0,0 +1,272 @@
+---
+title: async function
+slug: Web/JavaScript/Reference/Statements/async_function
+tags:
+ - JavaScript
+ - async
+ - Функція
+ - приклад
+translation_of: Web/JavaScript/Reference/Statements/async_function
+---
+<div>
+<div>{{jsSidebar("Statements")}}</div>
+
+<p><span class="seoSummary">Оголошення <code><strong>async function</strong></code> визначає <strong>асинхронну функцію</strong> — функцію, яка є об'єктом {{jsxref("Global_Objects/AsyncFunction","AsyncFunction")}}.</span> Асинхронні функції мають окремий від решти функцій порядок виконання, через <a href="/uk/docs/Web/JavaScript/EventLoop">цикл подій</a>, вертаючи неявний {{jsxref("Promise","проміс")}} в якості результату. Але синтаксис та структура коду, який використовує асинхронні функції, виглядають, як стандартні синхронні функції.</p>
+
+<div class="noinclude">
+<p>Ви також можете визначити асинхронну функцію за допомогою {{jsxref("Operators/async_function", "виразу async function", "", 1)}}.</p>
+</div>
+</div>
+
+<div>{{EmbedInteractiveExample("pages/js/statement-async.html", "taller")}}</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>
+
+<h2 id="Синтаксис">Синтаксис</h2>
+
+<pre class="syntaxbox">async function <em>name</em>([<em>param</em>[, <em>param</em>[, ... <em>param</em>]]]) {
+ <em>statements</em>
+}
+</pre>
+
+<h3 id="Параметри">Параметри</h3>
+
+<dl>
+ <dt><code>name</code></dt>
+ <dd>Ім'я функції.</dd>
+</dl>
+
+<dl>
+ <dt><code>param</code></dt>
+ <dd>Ім'я аргумента, що передається у функцію.</dd>
+</dl>
+
+<dl>
+ <dt><code>statements</code></dt>
+ <dd>Інструкції, що складають тіло функції.</dd>
+</dl>
+
+<h3 id="Значення_що_повертається">Значення, що повертається</h3>
+
+<p>Об'єкт <code><a href="/uk/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a></code>, який буде вирішений зі значенням, поверненим асинхронною функцією, або відхилений з винятком, не перехопленим всередині асинхронної функції.</p>
+
+<h2 id="Опис">Опис</h2>
+
+<p>Асинхронна функція може містити вираз {{jsxref("Operators/await", "await")}}, який призупиняє виконання функції, щоб дочекатись на вирішення об'єкта <code>Promise</code>, після чого відновлює виконання асинхронної функції та повертає вирішене значення.<br>
+ <br>
+ <strong>Ключове слово <code>await</code> працює тільки всередині асинхронних функцій.</strong> Якщо ви використаєте його поза межами тіла асинхронної функції, то отримаєте помилку <code><a href="/uk/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError">SyntaxError</a></code>.</p>
+
+<p>Поки асинхронна функція призупинена, функція, що її викликала, продовжує виконання (отримавши неявний проміс, повернений асинхронною функцією).</p>
+
+<div class="note">
+<p>Метою <code>async</code>/<code>await</code> є спрощення синхронного використання промісів, а також виконання певних дій над групою промісів. Як проміси схожі на структуровані зворотні виклики, так використання <code>async</code>/<code>await</code> схоже на поєднання <a href="/uk/docs/Web/JavaScript/Guide/Iterators_and_Generators">генераторів</a> та промісів.</p>
+</div>
+
+<h2 id="Приклади">Приклади</h2>
+
+<h3 id="Асинхронні_функції_та_порядок_виконання">Асинхронні функції та порядок виконання</h3>
+
+<pre class="brush: js">function resolveAfter2Seconds() {
+  console.log("починається повільний проміс")
+  return new Promise(resolve =&gt; {
+    setTimeout(function() {
+      resolve("повільний")
+      console.log("повільний проміс завершено")
+    }, 2000);
+  });
+}
+
+function resolveAfter1Second() {
+  console.log("починається швидкий проміс")
+  return new Promise(resolve =&gt; {
+    setTimeout(function() {
+      resolve("швидкий")
+      console.log("швидкий проміс завершено")
+    }, 1000);
+  });
+}
+
+async function sequentialStart() {
+  console.log('==ПОСЛІДОВНИЙ СТАРТ==')
+
+  // 1. Виконання доходить сюди майже миттєво
+  const slow = await resolveAfter2Seconds()
+  console.log(slow) // 2. це виконується 2 секунди після 1.
+
+  const fast = await resolveAfter1Second()
+  console.log(fast) // 3. це виконується 3 секунди після 1.
+}
+
+async function concurrentStart() {
+  console.log('==КОНКУРЕНТНИЙ СТАРТ з await==')
+  const slow = resolveAfter2Seconds() // запускає таймер негайно
+  const fast = resolveAfter1Second() // запускає таймер негайно
+
+  // 1. Виконання доходить сюди майже миттєво
+  console.log(await slow) // 2. це виконується 2 секунди після 1.
+  console.log(await fast) // 3. це виконується 2 секунди після 1., одразу після 2., оскільки швидкий вже вирішений
+}
+
+function concurrentPromise() {
+  console.log('==КОНКУРЕНТНИЙ СТАРТ з Promise.all==')
+  return Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then((messages) =&gt; {
+    console.log(messages[0]) // повільний
+    console.log(messages[1]) // швидкий
+  });
+}
+
+async function parallel() {
+  console.log('==ПАРАЛЕЛЬНИЙ з await Promise.all==')
+
+  // Починає 2 "роботи" паралельно та чекає, поки обидві не завершаться
+  await Promise.all([
+      (async()=&gt;console.log(await resolveAfter2Seconds()))(),
+      (async()=&gt;console.log(await resolveAfter1Second()))()
+  ])
+}
+
+// Ця функція не обробляє помилки. Дивіться застереження нижче!
+function parallelPromise() {
+  console.log('==ПАРАЛЕЛЬНИЙ з Promise.then==')
+  resolveAfter2Seconds().then((message)=&gt;console.log(message))
+  resolveAfter1Second().then((message)=&gt;console.log(message))
+}
+
+sequentialStart() // через 2 секунди виводить "повільний", далі через ще 1 секунду "швидкий"
+
+// чекає, поки попередній завершиться
+setTimeout(concurrentStart, 4000) // через 2 секунди виводить "повільний", а потім "швидкий"
+
+// знову чекає
+setTimeout(concurrentPromise, 7000) // такий самий, як і concurrentStart
+
+// знову чекає
+setTimeout(parallel, 10000) // справді паралельний: через 1 секунду виводить "швидкий", потім ще через 1 секунду "повільний"
+
+// знову чекає
+setTimeout(parallelPromise, 13000) // такий самий, як і parallel
+</pre>
+
+<h4 id="await_та_паралелізм"><code>await</code> та паралелізм</h4>
+
+<p>У <code>sequentialStart</code> виконання відкладається на 2 секунди для першого <code>await</code>, а потім ще на секунду для другого <code>await</code>. Другий таймер не створюється, поки перший не завершиться, отже, код завершує виконання через 3 секунди.</p>
+
+<p>У <code>concurrentStart</code> обидва таймери створюються і потім очікуються у <code>await</code>. Таймери виконуються конкурентно, це означає, що код завершує виконання через 2, а не через 3 секунди, тобто, як найповільніший таймер.<br>
+ Однак, виклики <code>await</code> все одно запускаються один за одним, це означає, що другий <code>await</code> чекатиме, поки перший не завершиться. У цьому випадку результат швидшого таймера обробляється після повільнішого.</p>
+
+<p>Якщо ви бажаєте виконувати дві або більше робіт паралельно, ви маєте використовувати <code>await Promise.all([job1(), job2()])</code>, як це показано у прикладі <code>parallel</code>.</p>
+
+<div class="warning">
+<h4 id="asyncawait_проти_Promisethen_та_обробка_помилок"><code>async</code>/<code>await</code> проти Promise#then та обробка помилок</h4>
+
+<p>Більшість асинхронних функцій також можна написати як звичайні функції, що використовують проміси. Однак, асинхронні функції менш каверзні, коли доходить до обробки помилок.</p>
+
+<p>І <code>concurrentStart</code>, і <code>concurrentPromise</code> функціонально еквівалентні:</p>
+
+<ul>
+ <li>У <code>concurrentStart</code>, якщо будь-який з викликів з <code>await</code>-ом зазнає невдачі, виняток буде автоматично перехоплений, виконання асинхронної функції перерветься, а помилка спливе наверх через неявний проміс, що повертається.</li>
+ <li>Щоб те саме сталось у випадку з Promise, функція має потурбуватись щодо повернення об'єкту <code>Promise</code>, який захопить завершення функції. У <code>concurrentPromise</code> це означає повернення проміса з <code>Promise.all([]).then()</code> через <code>return</code>. До речі, попередня версія цього прикладу забула це зробити!</li>
+</ul>
+
+<p>Однак, асинхронні функції все ж можуть ковтати помилки.<br>
+ Візьміть для прикладу асинхронну функцію <code>parallel</code>. Якби вона не мала <code>await</code> (чи <code>return</code>) для повернення результату виклику <code>Promise.all([])</code>, будь-яка помилка не спливала б.<br>
+ В той час, як приклад <code>parallelPromise</code> виглядає простішим, він взагалі не обробляє помилки! Для цього знадобилося б схожа конструкція <code>return </code><code>Promise.all([])</code>.</p>
+</div>
+
+<h3 id="Заміна_ланцюжка_промісів_на_асинхронну_функцію">Заміна ланцюжка промісів на асинхронну функцію</h3>
+
+<p>API, який вертає {{jsxref("Promise")}}, створить ланцюжок промісів, і це розбиває функцію на багато частин. Розглянемо наступний код:</p>
+
+<pre class="brush: js">function getProcessedData(url) {
+ return downloadData(url) // вертає проміс
+ .catch(e =&gt; {
+ return downloadFallbackData(url) // вертає проміс
+ })
+ .then(v =&gt; {
+ return processDataInWorker(v) // вертає проміс
+ })
+}
+</pre>
+
+<p>його можна переписати єдиною асинхронною функцією наступним чином:</p>
+
+<pre class="brush: js">async function getProcessedData(url) {
+ let v
+ try {
+ v = await downloadData(url)
+ } catch(e) {
+ v = await downloadFallbackData(url)
+ }
+ return processDataInWorker(v)
+}
+</pre>
+
+<p>У наведеному вище прикладі немає оператора <code>await</code> після ключового слова <code>return</code>, тому що повернене значення <code>async function</code> неявно загортається у {{jsxref("Promise.resolve")}}.</p>
+
+<div class="blockIndicator note">
+<h4 id="return_await_promiseValue_проти_return_promiseValue"><code>return await promiseValue;</code> проти <code>return promiseValue;</code></h4>
+
+<p>Неявне загортання повернених значень у {{jsxref("Promise.resolve")}} не означає, що <code>return await promiseValue;</code> є функціонально еквівалентним <code>return promiseValue;</code></p>
+
+<p>Розглянемо наступну переробку наведеного вище коду, яка вертає null, якщо <code>processDataInWorker</code> відхиляється з помилкою:</p>
+
+<pre class="brush: js">async function getProcessedData(url) {
+ let v;
+ try {
+ v = await downloadData(url)
+ } catch(e) {
+ v = await downloadFallbackData(url)
+ }
+ try {
+ return await processDataInWorker(v) // Зауважте `return await` у порівнянні з `return`
+ } catch (e) {
+ return null
+ }
+}
+</pre>
+
+<p>Варіант <code>return processDataInWorker(v);</code> спричинив би відхилення об'єкта {{jsxref("Promise")}}, поверненого функцією, замість вирішення його зі значенням <code>null</code>, якщо <code>processDataInWorker(v)</code> відхилено.</p>
+
+<p>Це висвітлює тонку різницю між <code>return foo;</code> та <code>return await foo;</code> — <code>return foo;</code> негайно вертає <code>foo</code> і ніколи не викидає помилку, навіть якщо <code>foo</code> є промісом, який відхиляється. <code>return await foo;</code> <em>чекатиме</em> на вирішення чи відхилення <code>foo</code>, якщо це проміс, і викидає помилку <strong>до повернення</strong>, якщо його відхилено.</p>
+</div>
+
+<h2 id="Специфікації">Специфікації</h2>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Специфікація</th>
+ <th scope="col">Статус</th>
+ <th scope="col">Коментар</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>{{SpecName('ESDraft', '#sec-async-function-definitions', 'async function')}}</td>
+ <td>{{Spec2('ESDraft')}}</td>
+ <td>Початкове визначення у ES2017.</td>
+ </tr>
+ <tr>
+ <td>{{SpecName('ES8', '#sec-async-function-definitions', 'async function')}}</td>
+ <td>{{Spec2('ES8')}}</td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Сумісність_з_веб-переглядачами">Сумісність з веб-переглядачами</h2>
+
+<div>
+
+
+<p>{{Compat("javascript.statements.async_function")}}</p>
+</div>
+
+<h2 id="Див._також">Див. також</h2>
+
+<ul>
+ <li>{{jsxref("Operators/async_function", "вираз асинхронної функції")}}</li>
+ <li>Об'єкт {{jsxref("AsyncFunction")}}</li>
+ <li>{{jsxref("Operators/await", "await")}}</li>
+ <li><a href="http://innolitics.com/10x/javascript-decorators-for-promise-returning-functions/">"Decorating Async Javascript Functions" на "innolitics.com"</a></li>
+</ul>