Яка різниця між обіцянками JavaScript та асинхронністю?


97

Я вже використовую функції ECMAScript 6 та ECMAScript 7 (завдяки Babel) у своїх додатках - як для мобільних, так і для Інтернету.

Очевидно, першим кроком було досягнення рівня ECMAScript 6. Я дізнався багато асинхронних зразків, обіцянки (які насправді є багатообіцяючими), генератори (не впевнений, чому символ *) тощо. Із них обіцянки досить добре підходили моїй меті. І я досить часто використовую їх у своїх додатках.

Ось приклад / псевдокод того, як я реалізував базову обіцянку -

var myPromise = new Promise(
    function (resolve,reject) {
      var x = MyDataStore(myObj);
      resolve(x);
    });

myPromise.then(
  function (x) {
    init(x);
});

Йшов час, я натрапив на ECMAScript 7 ознак, і один з них ASYNCі AWAITключових слів / функції. Вони разом роблять великі чудеса. Я почав замінювати деякі свої обіцянки на async & await. Здається, вони додають великої цінності стилю програмування.

Знову ж, ось псевдокод того, як виглядає моя функція async, await -

async function myAsyncFunction (myObj) {
    var x = new MyDataStore(myObj);
    return await x.init();
}
var returnVal = await myAsyncFunction(obj);

Не враховуючи синтаксичні помилки (якщо такі є), обидва вони роблять абсолютно те саме, що я відчуваю. Я майже зміг замінити більшість своїх обіцянок асинхронними, чекає.

Чому асинхронізація потрібна, коли обіцянки виконують подібну роботу?

Асинхронізація очікує вирішення більшої проблеми? Або це було просто інше рішення для зворотного виклику пекла?

Як я вже говорив раніше, я можу використовувати обіцянки та асинхронізацію, чекаючи вирішення тієї ж проблеми. Чи є щось конкретне, що асинхронізація чекає вирішення?

Додаткові нотатки:

Я широко використовував async, очікування та обіцянки у своїх проектах React та модулях Node.js. Особливо React був ранньою птицею і прийняв багато функцій ECMAScript 6 та ECMAScript 7.


3
Здається, у вашому першому блоці коду використовується обіцянка для синхронної операції. Чому ви це робите? Синхронний, за своєю природою, простіше писати код, тому не повинно бути жодної причини, щоб обернути синхронну операцію в обіцянку і змусити її тепер бути асинхронною.
jfriend00

@ jfriend00 Так, ти маєш рацію. Редагував код. Дякую.
bozzmob

2
Ви все ще намагаєтесь використовувати асинхронні інструменти з синхронними функціями - тепер в обох блоках коду. Чому?
jfriend00

@ jfriend00 Добре. Тут я маю свій код gist.github.com/bozzmob/26d38b83dc37d1be37f5 . Будь ласка, скажіть мені, що я роблю не так?
bozzmob

10
Здається, вам просто потрібно багато читати, щоб зрозуміти, для чого потрібні асинхронізація та очікування. Ось декілька статей: Довгий шлях до Async / Await у JavaScript та спрощення асинхронного кодування за допомогою асинхронних функцій ES7 та приручення асинхронного звіра за допомогою ES7 .
jfriend00

Відповіді:


75

Чому асинхронізація потрібна, коли Promises робить подібну роботу? Асинхронізація очікує вирішення більшої проблеми?

async/awaitпросто дає вам синхронне відчуття асинхронного коду. Це дуже елегантна форма синтаксичного цукру.

Для простих запитів та маніпулювання даними Promises може бути простим, але якщо ви стикаєтесь із сценаріями, коли є складні маніпуляції з даними і що не пов’язано, легше зрозуміти, що відбувається, якщо код просто виглядає так, ніби він синхронний (інакше кажучи, синтаксис сам по собі є формою "випадкової складності", яку async/awaitможна обійти).

Якщо вам цікаво дізнатись, ви можете скористатися бібліотекою типу co(поряд із генераторами), щоб дати такий самий вигляд. Такі речі розроблені для вирішення проблеми, яка async/awaitврешті-решт вирішується (власним шляхом).


Будь ласка, чи можете ви детальніше пояснити, що означає "випадкова складність"? Крім того, що стосується продуктивності, між ними немає різниці?
bozzmob

@bozzmob, shaffner.us/cs/papers/tarpit.pdf <- він пояснює "випадкову складність" там. Що стосується Вашого питання продуктивності, то я сумніваюся, особливо з тим, що є двигуном V8. Я впевнений, що є кілька тестів на перфорацію, але я б не переживав надто над цим. Не витрачайте час на мікрооптимізацію, коли це не потрібно.
Джош Бім

1
Дуже дякую! Це чудова інформація, яку я отримав від вас. І так, не буду розглядати мікрооптимізацію.
bozzmob

Я знайшов це пояснення корисним nikgrozev.com/2015/07/14/…
mwojtera

33

Async / Await забезпечують набагато приємніший синтаксис у більш складних сценаріях. Зокрема, все, що стосується циклів або деяких інших конструкцій, таких як try/ catch.

Наприклад:

while (!value) {
  const intermediate = await operation1();
  value = await operation2(intermediate);
}

Цей приклад був би значно складнішим лише за допомогою Promises.


Це чудовий приклад зрозуміти те саме. Отже, що стосується продуктивності, то між ними немає різниці? А що краще використовувати в коді? Async Await здається кращим, побачивши принаймні ваш приклад.
bozzmob

1
@bozzmob: Немає різниці в продуктивності. Якщо вам зручно використовувати async / await, я б рекомендував це. Сам я цим ще не користуюся, оскільки насправді це не є частиною офіційного стандарту.
Стівен Клірі

Так, я погоджуюсь, що він не є частиною стандарту, але у випадку ReactJS (реагувати рідно), я змушений використовувати його в деяких частинах коду. Отже, половина з них - це обіцянки, а половина - асинхронні очікування. Отже, я задав вам ці питання. Дякую за потрібну інформацію.
bozzmob

1
Я думаю, що багато людей розгублені та / або введені в оману, коли ніхто не використовує блок try / catch у своїх зразках коду.
Огі Гарднер

Ви маєте на увазі так? const getValue = value => value || operation1().then(operation2).then(getValue);
Шарку

13

Чому асинхронізація потрібна, коли Promises робить подібну роботу? Асинхронізація очікує вирішення більшої проблеми? чи це було просто інше рішення для зворотного виклику пекла? Як я вже говорив раніше, я можу використовувати Promises та Async, Await для вирішення тієї ж проблеми. Чи є щось конкретне, що вирішив Async Await?

Перше, що ви повинні зрозуміти, що async/ awaitсинтаксис - це просто синтаксичний цукор, який покликаний збільшити обіцянки. Насправді повернене значення asyncфункції є обіцянкою. async/ awaitсинтаксис дає нам можливість писати асинхронно синхронно. Ось приклад:

Мережа обіцянок:

function logFetch(url) {
  return fetch(url)
    .then(response => response.text())
    .then(text => {
      console.log(text);
    }).catch(err => {
      console.error('fetch failed', err);
    });
}

Async функція:

async function logFetch(url) {
  try {
    const response = await fetch(url);
    console.log(await response.text());
  }
  catch (err) {
    console.log('fetch failed', err);
  }
}

У наведеному вище прикладі awaitочікує, коли обіцянка ( fetch(url)) буде вирішена або відхилена. Якщо обіцянку вирішено, значення зберігається у responseзмінній, і якщо обіцянку відхилено, вона видасть помилку і, таким чином, введе catchблок.

Ми вже бачимо, що використання async/ awaitможе бути більш читабельним, ніж ланцюжок обіцянок. Це особливо актуально, коли кількість обіцянок, які ми використовуємо, збільшується. І обіцянка ланцюжка, і async/ awaitвирішення проблеми зворотного виклику, і вибраний вами метод - це питання особистих переваг.


7

Повне порівняння з плюсами і мінусами.

Звичайний JavaScript

  • Плюси
  • Не вимагає додаткових бібліотек або технологій
  • Пропонує найкращі показники
  • Забезпечує найкращий рівень сумісності зі сторонніми бібліотеками
  • Дозволяє створювати спеціальні та вдосконалені алгоритми
  • Мінуси
  • Може знадобитися додатковий код і відносно складні алгоритми

Async (бібліотека)

  • Плюси
  • Спрощує найпоширеніші схеми управління потоками
  • Це все ще рішення на основі зворотного дзвінка
  • Хороша продуктивність
  • Мінуси
  • Вводить зовнішню залежність
  • Все одно може бути недостатньо для просунутих потоків

Обіцянки

  • Плюси
  • Значно спрощує найпоширеніші схеми управління потоками
  • Надійна обробка помилок
  • Частина специфікації ES2015
  • Гарантії відкладеного виклику onFulfilled та onRejected
  • Мінуси
  • Потрібні API на основі promisify на основі зворотного виклику
  • Представляє невеликий хіт виконання

Генератори

  • Плюси
  • Неблокуючий API виглядає як блокуючий
  • Простота обробки помилок
  • Частина специфікації ES2015
  • Мінуси
  • Потрібна додаткова контрольна бібліотека потоків
  • Все ще потрібні зворотні дзвінки або обіцянки щодо здійснення послідовних потоків
  • Потрібні інтерфейси API на основі генераторів

Асинхронізація чекає

  • Плюси
  • Неблокуючий API виглядає як блокування
  • Чистий та інтуїтивно зрозумілий синтаксис
  • Мінуси
  • Потрібні Babel або інші компілятори та певна конфігурація, яка використовується сьогодні

Звідки це було скопійовано? Принаймні частина з них є на сторінці 136-137 у книзі Node.js Design Patterns (друге видання) (ISBN-10: 1785885588)
Пітер Мортенсен

6

Async / await може допомогти зробити ваш код чистішим та читабельнішим у випадках, коли вам потрібен складний потік управління. Він також виробляє більш зручний для налагодження код. І дає можливість обробляти як синхронні, так і асинхронні помилки просто try/catch.

Нещодавно я написав цю публікацію, демонструючи переваги async / await перед обіцянками в деяких поширених випадках використання з прикладами коду: 6 причин, чому JavaScript Async / Await збиває обіцянки (Підручник)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.