Async / Await: герой JavaScript заслуживает

  1. Мир сегодня
  2. Почему это происходит?
  3. утопия
  4. Делать улучшения
  5. Выгоды
  6. Завершение

Написание асинхронного кода сложно. Когда дело доходит до JavaScript, мы в значительной степени полагаемся на функции обратного вызова для выполнения асинхронных задач, которые могут быть далеко не интуитивными. Эти когнитивные издержки создают барьер для входа для новичков в программировании и языке и даже вызывают частые изжоги у тех из нас, кто некоторое время использовал этот язык.

В этой статье мы рассмотрим, как можно использовать предложение для ECMAScript 2016 (ES7), чтобы улучшить наш опыт работы с асинхронным программированием в JavaScript , делая наш код легче для понимания и проще для написания.

Мир сегодня

Давайте начнем с рассмотрения попытки асинхронного программирования сегодня. В следующем примере используется запрос библиотека, чтобы сделать HTTP-запрос к API Ron Swanson Quotes и распечатать ответ на консоль. Сделайте это, вставив следующее в файл с именем app.js и запустив npm install для установки зависимости. Если у вас не установлен Node.js, вы можете получить его из Вот ,

var request = require ('request'); function getQuote () {var quote; request ('http: //ron-swanson-quotes.herokuapp.com/v2/quotes', function (error, response, body) {quote = body;}); возврат цитаты; } function main () {var quote = getQuote (); приставка . журнал (цитата); } главный ();

Если вы работали с асинхронным программированием в JavaScript раньше, возможно, вы уже заметили, почему мы не получим цитату из этого кода. Если это так, то высокие пять.

Запустив его с узлом app.js, вы быстро увидите распечатанное неопределенное.

Почему это происходит?

Причина, по которой переменная кавычки не определена, заключается в том, что функция обратного вызова, которая ее назначает, не вызывается до тех пор, пока не завершится вызов функции запроса. Но поскольку функция запроса выполняется асинхронно, JavaScript не ждет, пока она завершится. Вместо этого он переходит к следующему оператору, который возвращает неназначенную переменную. Для лучшего объяснения того, как асинхронность в JavaScript работает под капотом, посмотрите этот удивительный разговор Филип Робертс в ЗАО на ЕС.

Синхронный код, как правило, легче понять и написать, потому что все выполняется в том порядке, в котором он написан. Операторы return широко используются и довольно интуитивно понятны в других языках, но, к сожалению, мы не можем использовать их так, как хотелось бы в JavaScript, потому что они плохо работают с асинхронной природой JavaScript.

Так зачем проходить борьбу с асинхронным кодом? Спектакль. Сетевые запросы и чтение с диска - это то, что мы называем операциями ввода / вывода (ввода / вывода). При синхронном выполнении ввода / вывода программа блоки , сидя и ожидая завершения передачи данных. Если для завершения запроса к базе данных требуется 60 секунд, программа бездействует в течение 60 секунд. Однако во время асинхронной операции ввода-вывода программа может возобновить нормальное выполнение и обрабатывать результаты операции ввода-вывода всякий раз, когда они появляются. Вот почему существуют функции обратного вызова, но с обратными вызовами работать гораздо сложнее, и при чтении исходного кода приложения они не работают.

утопия

Можем ли мы получить лучшее из обоих миров - асинхронный код, который позволяет нам работать с блокирующими операциями, но также легче читать и писать? Ответ да благодаря ES7 предложение для асинхронных функций (Async / Await).

Когда функция объявлена ​​как асинхронная, она может выполнить выполнение вызывающему коду, ожидая разрешения обещания. Если вы не знакомы с обещаниями, посмотрите один из эти отличный Ресурсы.

Вы можете заменить код в app.js следующим. Нам также нужно будет установить галдеж Транспортер для запуска. Сделайте это с помощью npm install babel. Babel превратит наш новейший код ES7 в версию, которая работает в современных условиях. Вы можете узнать больше о Вавилоне Вот ,

var request = require ('request'); function getQuote () {var quote; вернуть новое обещание (функция (разрешить, отклонить) {запрос ('http: //ron-swanson-quotes.herokuapp.com/v2/quotes', функция (ошибка, ответ, тело) {quote = body; разрешить (quote) ;});}); } асинхронная функция main () {var quote = await getQuote (); приставка . журнал (цитата); } главный (); приставка . журнал («Рон однажды сказал»);

Вы можете видеть, что мы возвращаем обещание, которое оборачивает сетевой запрос внутри нашей новой функции getQuote.

Внутри обратного вызова, переданного запросу, мы вызываем функцию разрешения обещания с телом результата.

Выполните следующее, чтобы запустить этот пример.

./ node_modules /. bin / babel - узел приложения. js // Рон однажды сказал, // {"quote": "Еда на завтрак может служить многим целям."}

Ого. Этот код выглядит довольно круто и близок к первоначальной попытке. Это выглядит довольно синхронно, хотя это не так.

«Если вы не заметили, - сказал однажды Рон, - сначала напечатали, несмотря на то, что его вызвали после мэйн» Это показывает, что мы не блокируем в ожидании завершения сетевого запроса.

Делать улучшения

На самом деле мы можем улучшить это, добавив обработку ошибок с помощью блока try / catch. Если во время запроса произошла ошибка, мы можем вызвать функцию отклонения обещания, которая будет обнаружена как ошибка внутри main. Как и операторы return, блоки try / catch в прошлом использовались очень редко, поскольку их было трудно правильно использовать с асинхронным кодом.

var request = require ('request'); function getQuote () {вернуть новое обещание (функция (разрешить, отклонить) {запрос ('http: //ron-swanson-quotes.herokuapp.com/v2/quotes', function (error, response, body) {if (error ) возврат отклонить (ошибка); решить (тело);});}); } асинхронная функция main () {try {var quote = await getQuote (); приставка . журнал (цитата); } catch (error) {console. ошибка (error); } } главный (); приставка . журнал («Рон однажды сказал»);

Запустите этот код еще раз, и вы увидите, что исключение перехватывается, если изменить URL-адрес запроса на что-то вроде http: // foo.

Выгоды

Это довольно удивительные преимущества, которые действительно изменят способ написания асинхронного JavaScript. Возможность писать код, который выполняется асинхронно, но выглядит синхронно и упрощает использование общих программных конструкций, таких как return и try / catch, безусловно, поможет сделать язык более доступным.

Самое приятное, что мы можем использовать нашу новую любимую функцию со всем, что возвращает обещание. Давайте возьмем Библиотека Twilio Node.js например. Если вы еще не использовали библиотеку Twilio Node.js, прежде чем сможете узнать больше об этом Вот , Вы также должны иметь учетную запись Twilio, на которую вы можете зарегистрироваться Вот ,

Начните с запуска npm и установите twilio. Затем вставьте следующее в файл с именем twilio.js и замените поля в строках, помеченных // TODO, своими учетными данными и номерами.

./ node_modules /. bin / babel - узел twilio. js var twilio = require ('twilio'); var client = новый twilio ('YOUR_TWILIO_ACCOUNT_SID', 'YOUR_TWILIO_AUTH_TOKEN'); // Асинхронная функция TODO sendTextMessage (to) {try {await client. Сообщения . create ({to: to, from: 'YOUR_TWILIO_PHONE_NUMBER', // тело TODO: 'Hello, Async / Await!'}); приставка . журнал («Запрос отправлен»); } catch (error) {console. ошибка (error); }} sendTextMessage ('YOUR_PHONE_NUMBER'); // Консоль TODO. log («Я печатаю первым, чтобы показать, что я асинхронный!»);

Как мы показали выше с функцией getQuote, мы пометили sendTextMessage как async, что позволяет ему ожидать разрешения обещания, возвращенного из client.sendMessage.

Завершение

Мы видели, как мы можем воспользоваться предложенной функцией ES7 для улучшения нашего опыта написания асинхронного JavaScript.

Я очень рад за предложение Async / Await двигаться вперед. Пока мы ждем этого, мы можем использовать Babel, чтобы воспользоваться этим сегодня с чем угодно, что возвращает обещание. Предложение недавно достигло стадии кандидата (стадия 3) и нуждается в использовании и Обратная связь ,

Попробуйте использовать его со следующей замечательной вещью, которую вы создадите, и обязательно сообщите мне об этом в комментариях или в Твиттере @eddiezane , И обязательно попробуйте Twilio's JavaScript и Node.js Учебники а также руководства на нашем сайте документации.

Почему это происходит?
Так зачем проходить борьбу с асинхронным кодом?