<
  • Главная
Статьи

Спрощення асинхронного коду на JavaScript з впровадженням асинхронних функцій з ES2016

  1. Асинхронні функції в ES7 / ES2016
  2. Як це реалізовано в Chakra?
  3. глобальне поведінку
  4. Поведінка з аргументом за замовчуванням
  5. Як включити підтримку асинхронних функцій Microsoft Edge?

Асинхронні функції в ES7 / ES2016

Ключові слова async і await, як частина пропозиції щодо впровадження асинхронних функцій, націлені на спрощення написання асинхронного коду. Це одна з ключових можливостей сучасного C # і часто запитувана опція з боку JavaScript-розробників . До введення асинхронних функцій і Проміс (promise) JS-розробнику доводилося обертати весь асинхронний код в окремі від синхронного коду функції і використовувати функції зворотного виклику (callback) для роботи з результатом асинхронного обчислення. Такий код досить швидко стає важко читати і підтримувати.
Проміс з ES, пройшовши через стандартизацію і отримуючи все більшу пряму підтримку в браузерах, допомогли поліпшити спосіб написання асинхронного коду, але не вирішили проблему повністю, так як потреба в написанні функцій зворотного виклику нікуди не зникла.
Асинхронні функції базуються на Проміс і дозволяють зробити наступний крок. Коли ви додаєте ключове слово async до функції або стрілочної функції, вона автоматично буде повертати промис. Наприклад, наступний код - це типова програма на ES2015, що робить http-запит за допомогою Проміс:

// ES6 code, without async / await function httpGet (url) {return new Promise (function (resolve, reject) {// do the usual Http request var request = new XMLHttpRequest (); request.open ( 'GET', url ); request.onload = function () {if (request.status == 200) {resolve (request.response);} else {reject (Error (request.statusText));}}; request.onerror = function () {reject (Error ( 'Network Error'));}; request.send ();}); } Function httpGetJson (url) {return new Promise (function (resolve, reject) {// check if the URL looks like a JSON file and call httpGet. Var regex = /\.(json)$/i; if (regex. test (url)) {// call the promise, wait for the result resolve (httpGet (url) .then (function (response) {return response;}, function (error) {reject (error);}));} else {reject (Error ( 'Bad File Format'));}}); } HttpGetJson ( 'file.json'). Then (function (response) {console.log (response);}). Catch (function (error) {console.log (error);});

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

// ES7 code, with async / await function httpGet (url) {return new Promise (function (resolve, reject) {// do the usual Http request let request = new XMLHttpRequest (); request.open ( 'GET', url ); request.onload = function () {if (request.status == 200) {resolve (request.response);} else {reject (Error (request.statusText));}}; request.onerror = function () {reject (Error ( 'Network Error'));}; request.send ();}); } Async function httpGetJson (url) {// check if the URL looks like a JSON file and call httpGet. let regex = /\.(json)$/i; if (regex.test (url)) {// call the async function, wait for the result return await httpGet (url); } Else {throw Error ( 'Bad Url Format'); }} HttpGetJson ( 'file.json'). Then (function (response) {console.log (response);}). Catch (function (error) {console.log (error);});

Ключове слово async також працює зі стрілочними функціями ES6 , Досить просто додати ключове слово перед аргументами. Ось невеликий приклад:

// call the async function, wait for the result let func = async () => await httpGet (url); return await func ();

Разом:

  • Використовуйте ключове слово async при визначенні будь-якої функції або стрілочної функції, щоб отримати асинхронний код з Проміс. Це включає також функції в класах і статичні функції. В останньому випадку ключове слово async потрібно вказувати після слова static і, відповідно, перед ім'ям функції.
  • Використовуйте ключове слово await, щоб хід виконання дочекався завершення async-вирази (наприклад, виклику async -функції) і отримало значення з Проміс.
  • Якщо ви не використовуєте ключове слово await, ви отримаєте сам промис.
  • Ви не можете використовувати ключове слово await поза async -функції, в тому числі його не можна використовувати в глобальному просторі.

Як це реалізовано в Chakra?

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

глобальне поведінку

Використання ключового слова async генерує конструктор Проміс, який, відповідно до специфікації, є обгорткою навколо вмісту функції. Для виконання цієї дії, генератор байт-коду Chakra формує виклик вбудованої функції, що реалізує наступне поведінка :

function spawn (genF, self) {return new Promise (function (resolve, reject) {var gen = genF.call (self); function step (nextF) {var next; try {next = nextF ();} catch (e ) {// finished with failure, reject the promise reject (e); return;} if (next.done) {// finished with success, resolve the promise resolve (next.value); return;} // not finished, chain off the yielded promise and `step` again Promise.resolve (next.value) .then (function (v) {step (function () {return gen.next (v);});}, function (e) { step (function () {return gen.throw (e);});});} step (function () {return gen.next (undefined);});}); }

Породжує функція, наведена вище, спроектована так, щоб обробити всі async -виражена в тілі функції і вирішити, чи потрібно продовжити або зупинити процес в залежності від поведінки всередині async -функції. Якщо async -вираження, викликане з ключовим словом await, провалюється, наприклад, внаслідок виникнення помилки усередині async -Функції або в цілому очікуваного вираження, то промис повертає відмову, який можна обробити вище по стеку.
Далі движок повинен викликати породжує функцію з JS-скрипта, щоб отримати промис і виконати вміст функції. Щоб це зробити, коли парсер знаходить ключове слово async, движок змінює AST (абстрактне синтаксичне дерево), що представляє алгоритм, щоб додати виклик spawn-функції з тілом цільової функції. Як наслідок, функція httpGetJson з прикладу вище конвертується парсером приблизно наступним чином:

function httpGetJson (url) {return spawn (function * () {// check if the URL looks like a JSON file and call httpGet. var regex = /\.(json)$/i; if (regex.test (url) ) {// call the async function, wait for the result return yield httpGet (url);} else {throw Error ( 'Bad Url Format');}}, this); }

Зверніть увагу на використання генераторів і ключового слова yield для реалізації поведінки ключового слова await. Насправді, реалізація підтримки ключового слова await дуже схожа на роботу з ключовим словом yield.

Поведінка з аргументом за замовчуванням

Одна з нових можливостей ES6 - це установка значення за замовчуванням для аргументу функції. Коли використовується значення за замовчуванням, генератор байт-коду встановить це значення на початку тіла функції.

// original JavaScript code function foo (argument = true) {// some stuff} // representation of the Bytecode Generator's output in JavaScript function foo (argument) {argument = true; // some stuff}

У разі використання ключового слова async, якщо значення за замовчуванням призводить до виникнення помилки (виключення), специфікація вимагає відмовити у виконанні Проміс. Це дозволяє з легкістю відловлювати виключення.
Щоб реалізувати це в Chakra, у команди був вибір з двох варіантів: змінити AST, або реалізувати таку поведінку безпосередньо в генераторі байт-коду. Ми вибрали друге і пересунули ініціалізацію аргументів на початок тіла функції безпосередньо в байт-коді, так як це більш просте і зрозуміле рішення в рамках нашого движка. Так як для перехоплення помилок з значення за замовчуванням потрібно було додати блок try / catch, то нам було простіше просто змінити байт-код при виявленні ключового слова async.
Нарешті, згенерований байт-код буде нагадувати результат, який створюється для такого коду на JavaScript:

// representation of the Bytecode Generator's output in JavaScript function foo (argument) {try {argument = true; } Catch (error) {return Promise.reject (error); } Return spawn (function * () {// keep this call as we are in an async function // some stuff}, this); }

Як включити підтримку асинхронних функцій Microsoft Edge?

Щоб включити експериментальну підтримку асинхронних функцій в Microsoft Edge, перейдіть на сторінку about: flags в Microsoft Edge і виберіть опцію "Enable experimental JavaScript features", як показано нижче:
Щоб включити експериментальну підтримку асинхронних функцій в Microsoft Edge, перейдіть на сторінку about: flags в Microsoft Edge і виберіть опцію Enable experimental JavaScript features, як показано нижче:   Асинхронні функції доступні в превью-режимі в рамках   програми Windows Insider   , Починаючи із збірки   Microsoft Edge 13
Асинхронні функції доступні в превью-режимі в рамках програми Windows Insider , Починаючи із збірки Microsoft Edge 13.10547 . Будемо раді почути ваші відгуки щодо використання даної функціональності в вашому коді в нашому Twitter @MSEdgeDev або через Connect .

Автор статті: Костянтин Кичинський

Як це реалізовано в Chakra?


Новости
  • Виртуальный хостинг

    Виртуальный хостинг. Возможности сервера распределяются в равной мере между всеми... 
    Читать полностью

  • Редизайн сайта

    Редизайн сайта – это полное либо частичное обновление дизайна существующего сайта.... 
    Читать полностью

  • Консалтинг, услуги контент-менеджера

    Сопровождение любых интернет ресурсов;- Знание HTML и CSS- Поиск и обновление контента;-... 
    Читать полностью

  • Трафик из соцсетей

    Сравнительно дешевый способ по сравнению с поисковым и контекстным видами раскрутки... 
    Читать полностью

  • Поисковая оптимизация

    Поисковая оптимизация (англ. search engine optimization, SEO) — поднятие позиций сайта в результатах... 
    Читать полностью