From 218934fa2ed1c702a6d3923d2aa2cc6b43c48684 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:43:23 -0500 Subject: initial commit --- .../reference/statements/async_function/index.html | 272 +++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 files/uk/web/javascript/reference/statements/async_function/index.html (limited to 'files/uk/web/javascript/reference/statements/async_function') 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 +--- +
+
{{jsSidebar("Statements")}}
+ +

Оголошення async function визначає асинхронну функцію — функцію, яка є об'єктом {{jsxref("Global_Objects/AsyncFunction","AsyncFunction")}}. Асинхронні функції мають окремий від решти функцій порядок виконання, через цикл подій, вертаючи неявний {{jsxref("Promise","проміс")}} в якості результату. Але синтаксис та структура коду, який використовує асинхронні функції, виглядають, як стандартні синхронні функції.

+ +
+

Ви також можете визначити асинхронну функцію за допомогою {{jsxref("Operators/async_function", "виразу async function", "", 1)}}.

+
+
+ +
{{EmbedInteractiveExample("pages/js/statement-async.html", "taller")}}
+ + + +

Синтаксис

+ +
async function name([param[, param[, ... param]]]) {
+   statements
+}
+
+ +

Параметри

+ +
+
name
+
Ім'я функції.
+
+ +
+
param
+
Ім'я аргумента, що передається у функцію.
+
+ +
+
statements
+
Інструкції, що складають тіло функції.
+
+ +

Значення, що повертається

+ +

Об'єкт Promise, який буде вирішений зі значенням, поверненим асинхронною функцією, або відхилений з винятком, не перехопленим всередині асинхронної функції.

+ +

Опис

+ +

Асинхронна функція може містити вираз {{jsxref("Operators/await", "await")}}, який призупиняє виконання функції, щоб дочекатись на вирішення об'єкта Promise, після чого відновлює виконання асинхронної функції та повертає вирішене значення.
+
+ Ключове слово await працює тільки всередині асинхронних функцій. Якщо ви використаєте його поза межами тіла асинхронної функції, то отримаєте помилку SyntaxError.

+ +

Поки асинхронна функція призупинена, функція, що її викликала, продовжує виконання (отримавши неявний проміс, повернений асинхронною функцією).

+ +
+

Метою async/await є спрощення синхронного використання промісів, а також виконання певних дій над групою промісів. Як проміси схожі на структуровані зворотні виклики, так використання async/await схоже на поєднання генераторів та промісів.

+
+ +

Приклади

+ +

Асинхронні функції та порядок виконання

+ +
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
+
+ +

await та паралелізм

+ +

У sequentialStart виконання відкладається на 2 секунди для першого await, а потім ще на секунду для другого await. Другий таймер не створюється, поки перший не завершиться, отже, код завершує виконання через 3 секунди.

+ +

У concurrentStart обидва таймери створюються і потім очікуються у await. Таймери виконуються конкурентно, це означає, що код завершує виконання через 2, а не через 3 секунди, тобто, як найповільніший таймер.
+ Однак, виклики await все одно запускаються один за одним, це означає, що другий await чекатиме, поки перший не завершиться. У цьому випадку результат швидшого таймера обробляється після повільнішого.

+ +

Якщо ви бажаєте виконувати дві або більше робіт паралельно, ви маєте використовувати await Promise.all([job1(), job2()]), як це показано у прикладі parallel.

+ +
+

async/await проти Promise#then та обробка помилок

+ +

Більшість асинхронних функцій також можна написати як звичайні функції, що використовують проміси. Однак, асинхронні функції менш каверзні, коли доходить до обробки помилок.

+ +

І concurrentStart, і concurrentPromise функціонально еквівалентні:

+ + + +

Однак, асинхронні функції все ж можуть ковтати помилки.
+ Візьміть для прикладу асинхронну функцію parallel. Якби вона не мала await (чи return) для повернення результату виклику Promise.all([]), будь-яка помилка не спливала б.
+ В той час, як приклад parallelPromise виглядає простішим, він взагалі не обробляє помилки! Для цього знадобилося б схожа конструкція return Promise.all([]).

+
+ +

Заміна ланцюжка промісів на асинхронну функцію

+ +

API, який вертає {{jsxref("Promise")}}, створить ланцюжок промісів, і це розбиває функцію на багато частин. Розглянемо наступний код:

+ +
function getProcessedData(url) {
+  return downloadData(url) // вертає проміс
+    .catch(e => {
+      return downloadFallbackData(url) // вертає проміс
+    })
+    .then(v => {
+      return processDataInWorker(v) // вертає проміс
+    })
+}
+
+ +

його можна переписати єдиною асинхронною функцією наступним чином:

+ +
async function getProcessedData(url) {
+  let v
+  try {
+    v = await downloadData(url)
+  } catch(e) {
+    v = await downloadFallbackData(url)
+  }
+  return processDataInWorker(v)
+}
+
+ +

У наведеному вище прикладі немає оператора await після ключового слова return, тому що повернене значення async function неявно загортається у {{jsxref("Promise.resolve")}}.

+ +
+

return await promiseValue; проти return promiseValue;

+ +

Неявне загортання повернених значень у {{jsxref("Promise.resolve")}} не означає, що return await promiseValue; є функціонально еквівалентним return promiseValue;

+ +

Розглянемо наступну переробку наведеного вище коду, яка вертає null, якщо processDataInWorker відхиляється з помилкою:

+ +
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
+  }
+}
+
+ +

Варіант return processDataInWorker(v); спричинив би відхилення об'єкта {{jsxref("Promise")}}, поверненого функцією, замість вирішення його зі значенням null, якщо processDataInWorker(v) відхилено.

+ +

Це висвітлює тонку різницю між return foo; та return await foo;return foo; негайно вертає foo і ніколи не викидає помилку, навіть якщо foo є промісом, який відхиляється. return await foo; чекатиме на вирішення чи відхилення foo, якщо це проміс, і викидає помилку до повернення, якщо його відхилено.

+
+ +

Специфікації

+ + + + + + + + + + + + + + + + + + + + + +
СпецифікаціяСтатусКоментар
{{SpecName('ESDraft', '#sec-async-function-definitions', 'async function')}}{{Spec2('ESDraft')}}Початкове визначення у ES2017.
{{SpecName('ES8', '#sec-async-function-definitions', 'async function')}}{{Spec2('ES8')}}
+ +

Сумісність з веб-переглядачами

+ +
+ + +

{{Compat("javascript.statements.async_function")}}

+
+ +

Див. також

+ + -- cgit v1.2.3-54-g00ecf