От «Шоссе в (обратный) ад» к «Лестнице в (асинхронный/ожидание) рай»​

Здравствуйте, я вернулся, чтобы немного поговорить о JavaScript. На этот раз я покажу, как JavaScript изменил свой способ работы с асинхронным кодом. Итак… приступим!!!

Обратные вызовы

(Не так уж) давно, когда нам нужно было работать с асинхронным кодом, мы использовали обратные вызовы, в то время, когда это было лучше всего, это было похоже на волшебство, мы создавали функции, которые выполнялись после того, как что-то было готово, ЭТО ЗАМЕЧАТЕЛЬНО не так ли?

NO!!!!

Я не скажу, что это самое худшее в мире, в то время это было здорово, но через какое-то время наш код уже не был таким красивым, и мы чувствовали себя как в аду! Давайте посмотрим на простой пример того, о чем я говорю. Давайте воспользуемся PokeAPI, чтобы получить некоторую информацию. Нам нужно сделать четыре запроса:

  1. Сначала информация о покемонах: http://pokeapi.co/api/v2/pokemon/1
  2. Во-вторых, мы сделаем запрос, чтобы получить информацию о его первом ходе.
  3. В-третьих, мы сделаем запрос, чтобы получить информацию о движущейся машине.
  4. В-четвертых, мы сделаем запрос на получение информации об элементе машины.
(function () {
  const API_BASE_URL = 'https://pokeapi.co/api/v2';
  let pokemonInfo = null;
  let moveInfo = null;
  let machineInfo = null;
  let itemInfo = null;

  const pokemonXHR = new XMLHttpRequest();
  pokemonXHR.responseType = 'json';
  pokemonXHR.open('GET', `${API_BASE_URL}/pokemon/1`);
  pokemonXHR.send();

  pokemonXHR.onload = function () {
    pokemonInfo = this.response
    
    const moveXHR = new XMLHttpRequest();
    moveXHR.responseType = 'json';
    moveXHR.open('GET', pokemonInfo.moves[0].move.url);
    moveXHR.send();
  
    moveXHR.onload = function () {
      moveInfo = this.response;
      
      const machineXHR = new XMLHttpRequest();
      machineXHR.responseType = 'json';
      machineXHR.open('GET', moveInfo.machines[0].machine.url);
      machineXHR.send();
      
      machineXHR.onload = function () {
        machineInfo = this.response;
        
        const itemXHR = new XMLHttpRequest();
      	itemXHR.responseType = 'json';
      	itemXHR.open('GET', machineInfo.item.url);
      	itemXHR.send();
        
        itemXHR.onload = function () {
          itemInfo = this.response;
          
          console.log('Pokemon', pokemonInfo);
          console.log('Move', moveInfo);
          console.log('Machine', machineInfo);
          console.log('Item', itemInfo);
        }
      }
    }
  }
})();

Как видите, это очень простой код, но он уже запутан большим количеством обратных вызовов. Теперь представьте эту ситуацию в крупномасштабном приложении… Разве это не то, что мы хотим поддерживать в течение длительного времени, верно?

Обещания

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

(function () {
  const API_BASE_URL = 'https://pokeapi.co/api/v2';
  let pokemonInfo = null;
  let moveInfo = null;
  let machineInfo = null;
  let itemInfo = null;
  
  const showResults = () => {
    console.log('Pokemon', pokemonInfo);
    console.log('Move', moveInfo);
    console.log('Machine', machineInfo);
    console.log('Item', itemInfo);
  };
  
  const getItemInfo = response => {
    itemInfo = response;
    showResults();
  };
  
  const getMachineInfo = response => {
    machineInfo = response;
    
    fetch(machineInfo.item.url)
      .then(res => res.json())
      .then(getItemInfo)
      .catch(err => console.log(err));
  };
  
  const getMoveInfo = response => {
    moveInfo = response;
    
    fetch(moveInfo.machines[0].machine.url)
      .then(res => res.json())
      .then(getMachineInfo)
      .catch(err => console.log(err));
  };
  
  const getPokemonInfo = response => {
    pokemonInfo = response;
    
    fetch(pokemonInfo.moves[0].move.url)
      .then(res => res.json())
      .then(getMoveInfo)
      .catch(err => console.log(err));
  };
  
  fetch(`${API_BASE_URL}/pokemon/1`)
    .then(res => res.json())
    .then(getPokemonInfo)
    .catch(err => console.log(err));
})();

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

асинхронно/ожидание

С промисами наш код намного красивее, чем раньше, когда мы использовали обратные вызовы, но код мог бы быть немного проще, мы могли бы написать меньше кода и сделать код еще лучше визуально. Мы можем сделать это, используя функцию async/await. Давайте посмотрим, как это работает:

const axios = require('axios');
const API_BASE_URL = 'https://pokeapi.co/api/v2';

let pokemonInfo;
let moveInfo;
let machineInfo;
let itemInfo;

function showResults () {
  return new Promise(resolve => {
    setTimeout(() => {
	  console.log('Pokemon', pokemonInfo.data);
	  console.log('Move', moveInfo.data);
	  console.log('Machine', machineInfo.data);
	  console.log('Item', itemInfo.data);
	  resolve('Finished!!!');
	}, 2000);
  });
}

async function init () {
  try {
    pokemonInfo = await axios(`${API_BASE_URL}/pokemon/1`);
	moveInfo = await axios(pokemonInfo.data.moves[0].move.url);
	machineInfo = await axios(moveInfo.data.machines[0].machine.url);
	itemInfo = await axios(machineInfo.data.item.url);

	console.log('Building results report...');
	const message = await showResults();
	console.log(message);
  } catch (error) {
	console.log('ERROR', error);
  }
}

init();

Посмотрите на приведенный выше код… Это УДИВИТЕЛЬНО!!! Мы написали всего несколько строк кода и сделали больше, чем с кодами, которые я показывал ранее, и код намного чище, чем другие!!!

Вывод

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

Я надеюсь, что вам понравилась эта статья и что она может быть вам полезна! Пока и до встречи в следующей статье!!! :D