У програмуванні, await — особливість, яка була впроваджена у C# 5.0, C++20, Python 3.5, Hack, Dart, Kotlin 1.1, експериментальному доповненні для Scala, «нічній» збірці Rust, і в нещодавніх версіях JavaScript. Вона дозволяє здійснити виклик асинхронного методу схожим чином, як викликаються звичайні, синхронні методи.
Базові операції Все, що роблять ключові слова async та await, є коригуванням коду під час компіляції. Для цього використовується клас Task, який зберігає стан операції.
Приклад коду, в якому використовується await: public async Task<int> FindPageSize(Uri uri) { var data = await new WebClient().DownloadDataTaskAsync(uri); return data.Length; } Тут завантажується URI та повертається його довжина. Ключове слово «async» вказує компілятору, що можна переорганізувати код всередині методу, щоб дозволити відкладати відмічені виклики й обгортати їхні результати в Task. Результатом функції FindPageSize є об'єкт типу Task<int> — це означає, що функція повертає ціле число, але воно може бути неготовим для використання, щойно керування повернулося з FindPageSize — на нього потрібно «зачекати».
Тому компілятор може скорегувати цей код до такого вигляду: public Task<int> FindPageSize(Uri uri) { var data_task = new WebClient().DownloadDataTaskAsync(uri); var after_data_task = data_task.ContinueWith((original_task) => { return original_task.Result.Length; }); return after_data_task; } async у сигнатурі методу дозволяє корегування коду з використанням Task і ContinueWith при кожному використанні await. Компілятор не змінить код, якщо await не використовується (C# видає попередження), а метод не буде асинхронним.
Task можна використовувати незалежно від await. «await» є синтаксичним цукром для спрощення роботи кінцевого користувача. Тобто, при кожному використанні await решта коду, що використовує результат асинхронної функції, обгортається у блок ContinueWith.
Також, в асинхронному методі не обов'язково використовувати await. При виклику асинхронної функції без використання await задача виконуватиметься у фоновому режимі. Змінну типу Task, яку повернула функція, можна використовувати для отримання інформації про стан завдання. Таким чином, можна запустити кілька асинхронних задач одночасно, зберегти їх у списку й отримати результат, передавши його до . Це дозволяє їм усім виконуватися одночасно, а потім просто очікує на виконання всіх задач. Це може бути набагато ефективніше за очікування завершення кожної з них. Наприклад, виконуючи 10 мережевих запитів, якщо розпочати їх усі одночасно (а не послідовно, використовуючи await), а потім очікувати виклик WhenAll, це може призвести до паралельного виконання всіх мережевих запитів.
В С#
До сьомої версії С# асинхронні методи обов'язково мають повертати void, Task, або Task<T>. Потім цей список поповнився іншими типами на кшталт ValueTask<T>. Асинхронні методи, які нічого не повертають, призначені для обробників подій. У більшості випадків результат асинхронного методу, який нічого не повертає, рекомендується позначати як Task, а не void, так як це сприяє інтуїтивному керуванню виключеннями.
Сигнатуру методів, що використовують await, треба позначати за допомогою async. У методах, які повертають змінні типу Task<T> та позначені асинхронними, має повертатися змінна типу T, а не Task<T>. Компілятор обгортає значення в Task<T>. Також передбачена можливість виклику функцій, які повертають задачу, через await, навіть якщо вони не позначені асинхронними.
Наведений нижче асинхронний метод, завантажує дані із URL використовуючи await. public async Task<int> SumPageSizesAsync(IList<Uri> uris) { int total = 0; foreach (var uri in uris) { statusText.Text = string.Format("Found {0} bytes ...", total); var data = await new WebClient().DownloadDataTaskAsync(uri); total += data.Length;
statusText.Text = string.Format("Found {0} bytes total", total); return total; }
В C++ В C++, await (який називається co_await в C++) був офіційно долучений до стандарту C++20; також компілятори MSVC та Clang вже підтримують co_await.
В JavaScript Оператор await в JavaScript може використовуватися лише в функції, що відмічена ключовим словом async. Якщо параметр є Promise-ом, виконання async-функції відновиться, коли Promise буде вирішено(resolved). Якщо Promise буде відхилий(rejected) - в цьому випадку буде викинута помилка, яка може бути оброблена з використанням звичайного сценарію виключення JavaScript. Якщо параметр не є Promise-ом, сам параметр буде повернуто негайно.
Багато бібліотек надають повертають Promise-об'єкти, які також можуть використовуватися в очікуванні, якщо вони узгоджуються з специфікацією для власних Promise-об'єктів JavaScript. Проте обіцянки з бібліотеки jQuery не були сумісними з власними Promis-об'єктами на рівні A+ аж до версії jQuery 3.0.
Приклад (взято з цієї статті):
async function createNewDoc() { let response = await db.post({}); // post a new doc return await db.get(response.id); // find by id }
async function main() { try { let doc = await createNewDoc(); console.log(doc); } catch (err) { console.log(err);
}()
Примітки