Skip to main content

await у стрілкових функціях

Так, await у стрілковій функції використовувати можна, але лише тоді, коли стрілка оголошена з ключовим словом async. Сама форма запису функції тут ні до чого: дозвіл на await дає async, а не стрілка чи function.

Теорія

TL;DR

  • await дозволений лише всередині async-функції або на верхньому рівні ES-модуля.
  • Стрілкова функція стає асинхронною так само просто: async () => { ... }.
  • Без async це SyntaxError, код не виконається взагалі, бо помилка виникає ще під час парсингу.
  • Будь-яка async-функція, зокрема стрілкова, завжди повертає проміс.
  • async-стрілку можна передавати як колбек, наприклад у .then(), і await усередині неї цілком легальний.
  • Поза функцією await працює тільки як top-level await в ESM.

Швидкий приклад

javascript
const fetchData = async () => { const data = await Promise.resolve('Готово'); console.log(data); }; fetchData();

Результат:

text
Готово

async перед стрілковою функцією перетворює її на асинхронну функцію, яка завжди повертає проміс.

Де взагалі дозволений await

await, це оператор, який можна вживати тільки в двох місцях:

  • усередині функції, оголошеної з async;
  • на верхньому рівні модуля (top-level await).

Якщо використати await поза async, буде синтаксична помилка:

javascript
// Помилка const result = await Promise.resolve(42); // SyntaxError: await is only valid in async functions

Те саме зі звичайною стрілкою без async:

javascript
const foo = () => { const data = await Promise.resolve('value'); console.log(data); }; // SyntaxError: await is only valid in async functions

Зверніть увагу: це не помилка часу виконання. JS навіть не почне виконувати код, бо await неприпустимий у звичайній функції, і скрипт падає ще на етапі розбору.

Що повертає async-стрілка

async-стрілка завжди повертає проміс, навіть якщо в ній немає жодного await:

javascript
const sum = async (a, b) => a + b; console.log(sum(1, 2)); // Promise { 3 }

Це те саме, що написати:

javascript
function sum(a, b) { return Promise.resolve(a + b); }

Тому результат такої функції треба або await-ити, або обробляти через .then().

Різні форми запису

Стрілка з await у звичайному вигляді:

javascript
const loadUser = async () => { const res = await fetch('/api/user'); return res.json(); };

З параметрами:

javascript
const getUser = async (id) => { const res = await fetch(`/api/user/${id}`); return res.json(); };

Багаторядкова форма:

javascript
const processData = async () => { const data = await fetch('/api/data'); const json = await data.json(); console.log(json); };

У ланцюжку промісів:

javascript
Promise.resolve('A') .then(async (x) => { const y = await Promise.resolve('B'); return x + y; }) .then(console.log); // "AB"

Тут then() приймає async-стрілкову функцію, і await усередині неї повністю легальний: then просто дочекається промісу, який ця функція поверне.

Top-level await

Сучасні JS-модулі (ESM) дозволяють використовувати await поза функціями, якщо код виконується саме як модуль, а не як звичайний <script> без type="module":

javascript
// main.js const data = await fetch('/api/data').then(r => r.json()); console.log(data);

Це і є top-level await. Він працює лише в ESM (у браузері з <script type="module"> або в Node.js з "type": "module" у package.json). У CommonJS-модулі такий код не запрацює.

Проста аналогія: async перед стрілковою функцією, це перепустка, яка дає право вживати await усередині. Без неї рушій просто не знає, куди повертати результат очікування.

Підсумкова таблиця

ПитанняВідповідь
Чи можна вживати await у стрілковій функції?Так, якщо вона оголошена як async
Що буде без async?SyntaxError: await is only valid in async functions
Що повертає async-стрілка?Завжди Promise
Чи можна await у .then() або колбеках?Так, якщо колбек оголошений як async
Чи можна await поза функцією?Тільки як top-level await у модулях

Типові помилки

  • Ставити await у звичайній стрілці й дивуватися, що не працює навіть код до нього: це помилка парсингу, а не виконання.
  • Забувати, що async-стрілка повертає проміс, і писати const x = sum(1, 2), отримуючи Promise, а не число.
  • Писати async на зовнішній функції, а await використовувати всередині вкладеного звичайного колбека, наприклад arr.forEach(item => { await save(item); }). Помічати треба саме той колбек: async item => ....
  • Чекати, що arr.forEach(async ...) дочекається всіх операцій: forEach ігнорує повернені проміси, потрібен for...of з await або Promise.all(arr.map(async ...)).
  • Використовувати top-level await у файлі, який завантажується як звичайний скрипт або як CommonJS: там він недоступний.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.