Рубрики
Без рубрики

Учите асинхронный JavaScript в 2018 году

Асинхронный характер JavaScript, вероятно, является одним из самых важных аспектов языка, который каждый должен освоить.

Автор оригинала: AJ Meyghani.

Ниже приведен выдержка из новейшей книги, которую я работал над «асинхронным JavaScript». Вы можете прочитать его онлайн бесплатно в asyncjsbook.com.

Если вы новичок в Async Programming в JavaScript, вы можете быть удивлены результатом следующего куска кода:

setTimeout(function() {
  console.log('1');
}, 0);
console.log('2');

Как вы думаете, что вывод вышеуказанного кода будет? Вы можете быть соблазн сказать 1 а потом 2 , но правильный ответ – 2 а потом 1 Отказ В следующих разделах мы будем нырять в асинхронную модель, используемую в JavaScript и объяснить, почему вышеуказанные принты Code 2 а потом 1 Отказ

Синхронные против асинхронные

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

Представьте, что у вас есть три задания, чтобы сделать в своем списке ежедневных домов:

  1. Стирать
  2. Делать бакареи
  3. готовить обед

С помощью синхронной модели вы должны закончить каждую задачу, прежде чем перейти к следующему. То есть вы должны сначала закончить прачечную, прежде чем переехать на просмотр продуктов. Если ваша прачечная сломана, вы не можете сделать продукты. То же самое относится и к третьей задаче, вы можете приготовить только ужин только если и только если вы завершили продукты (и белье).

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

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

Контур событий

Давайте посмотрим на фрагмент, который мы видели в начале главы:

setTimeout(function() {
  console.log('1');
}, 0);
console.log('2');

Когда вы называете Сетримс Метод, он будет нажата на то, что называется очередью сообщений. После этого console.log (2) будет вызван немедленно. После console.log (2) называется стеком пустой, а JavaScript перемещается на очередь и выполняет то, что на очереди. Механизм, который управляет этим потоком называется контуром события. Структура событий несет ответственность за то, что находится на стеке и очередь и планирование выполнения в правильном порядке. На рисунке ниже существует три задача на стеке. После того, как они закончится, еще два задания подбираются из очереди и помещены на стек, чтобы быть выполненным:

Event-Loop.png.png

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

Есть пара абстракций более высокого уровня, такие как обещания и Async/ждут, которые могут помочь вам написать Clean Async Code. Давайте поговорим о функциях обратного вызова, будем ли мы?

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

var name = 'Tom';
hello(name);

В приведенном выше фрагменте кода мы определяем переменную называемое имя, и мы назначаем на нее строку. Тогда мы передаем его на Привет Функция как аргумент. Мы можем сделать то же самое с функцией. Мы можем определить Имя быть функцией вместо этого и передать его на Привет :

function name() {
  return 'Tom';
}
hello(name);

Технически говоря Имя Функция обратного вызова, потому что она передается другому функции, но давайте посмотрим, какой функция обратного вызова находится в контексте асинхронной операции.

В Async-контексте функция обратного вызова – это просто нормальная функция JavaScript, которая вызывается JavaScript, когда асинхронная операция завершена. По соглашению функция обратного вызова обычно принимает два аргумента. Первые захватывающие ошибки, а второе охватывает результаты. Функция обратного вызова может быть названа или анонимным, но лучше их назвать. Давайте посмотрим на простой пример, показывающий, как прочитать содержимое файла асинхронно используя узел Fs.readfile Метод:

function handleReading(error, result) {
  console.log(result);
}
fs.readFile('./my-file.txt', handleReading);

ФС Модуль имеет метод под названием readfile Отказ Требуется два необходимых аргумента, первый – путь к файлу, а второй функция обратного вызова. В приведенном выше фрагменте функция обратного вызова – Handvereading это принимает два аргумента. Первые захватывающие потенциальные ошибки и второй захватывают содержание.

Ниже приведен еще один пример из https Модуль для создания Получить Запрос на удаленный сервер API:

Код/Callbacks/http-example.js

const https = require('https');
const url = 'https://jsonplaceholder.typicode.com/posts/1';

https.get(url, function(response) {
  response.setEncoding('utf-8');
  let body = '';
  response.on('data', (d) => {
    body += d;
  });
  response.on('end', (x) => {
    console.log(body);
  });
});

Когда вы называете получить Способ, запрос запланирован JavaScript. Когда результат доступен, JavaScript позвонит нашу функцию и предоставит нам результатом.

«Возвращение» асинхрониза

Когда вы выполняете операцию Async, вы не можете просто использовать Возвращение заявление, чтобы получить результат. Допустим, у вас есть функция, которая управляет асинковым вызовом. Если вы создаете переменную, и установите его в async Callback, вы не сможете получить результат из внешней функции, просто возвращая значение:

function getData(options) {
  var finalResult;
  asyncTask(options, function(err, result) {
    finalResult = result;
  })
  return finalResult;
}
getData(); // -> returns undefined

В фрагменте выше, когда вы звоните getdata , он немедленно выполняется, а возвращенное значение – undefined Отказ Это потому, что во время звонка функции FinalResult не настроен ни на что. Это только после более позднего момента во времени, чтобы значение устанавливается. Правильный способ упаковки асинкового вызова, состоит в том, чтобы пройти внешнюю функцию обратный вызов:

function getData(options, callback) {
  asyncTask(options, callback);
}
getData({}, function(err, result) {
  if(err) return console.log(err);
  console.log(result);
});

На фрагменте выше, мы определяем getdata Принять функцию обратного вызова в качестве второго аргумента. Мы также назвали его обратным вызовом, чтобы понять, что getdata ожидает функции обратного вызова в качестве второго аргумента.

Async задачи по порядку

Если у вас есть пара асинхронных задач, которые зависят друг над другом, вам придется позвонить каждой задаче в обратном вызове других задач. Например, если вам нужно скопировать содержимое файла, сначала нужно будет прочитать содержимое файла, прежде чем написать его в другой файл. Из-за этого вам нужно позвонить в writefile Метод в пределах readfile Перезвоните:

const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function readContent(err, content) {
  if(err) {
    return console.log(err);
  }
  fs.writeFile('copy.txt', content, function(err) {
    if(err) {
      return console.log(err);
    }
    return console.log('done');
  });
});

Теперь он может стать грязным, если у вас много операций ASYNC, которые зависят друг над другом. В этом случае лучше назвать каждую функцию обратного вызова и определить их отдельно, чтобы избежать путаницы:

const fs = require('fs');
fs.readFile('file.txt', 'utf-8', readCb);

function readCb(err, content) {
  if (err) {
    return console.log(err);
  }
  return fs.writeFile('copy.txt', content, writeCb);
}

function writeCb(err) {
  if(err) {
    return console.log(err);
  }
  return console.log('Done');
}

На фрагменте выше мы определили два функции обратного вызова отдельно, readcb и WriteCB Отказ Преимущества могут быть не очевидно из приведенного выше примера, но для операций, которые имеют несколько зависимостей, именованные функции обратного вызова могут сэкономить вам много волос вниз по линии.

Я работал над книгой, которая подробно объясняет другие асинхронистые абстракции. Вы можете бесплатно прочитать книгу онлайн бесплатно в asyncjsbook.com.