diff options
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.html | 272 |
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 => { + setTimeout(function() { + resolve("повільний") + console.log("повільний проміс завершено") + }, 2000); + }); +} + +function resolveAfter1Second() { + console.log("починається швидкий проміс") + return new Promise(resolve => { + 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) => { + console.log(messages[0]) // повільний + console.log(messages[1]) // швидкий + }); +} + +async function parallel() { + console.log('==ПАРАЛЕЛЬНИЙ з await Promise.all==') + + // Починає 2 "роботи" паралельно та чекає, поки обидві не завершаться + await Promise.all([ + (async()=>console.log(await resolveAfter2Seconds()))(), + (async()=>console.log(await resolveAfter1Second()))() + ]) +} + +// Ця функція не обробляє помилки. Дивіться застереження нижче! +function parallelPromise() { + console.log('==ПАРАЛЕЛЬНИЙ з Promise.then==') + resolveAfter2Seconds().then((message)=>console.log(message)) + resolveAfter1Second().then((message)=>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 => { + return downloadFallbackData(url) // вертає проміс + }) + .then(v => { + 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> |