Синхронная операция блокирует процесс до завершения операции. Асинхронная операция неблокирующая и только инициирует операцию. Завершение можно обнаружить и другими способами.

Чтобы понять, как работает асинхронизм в Javascript, давайте сначала поговорим о том, как promises раскрывает этот метод завершения.

Представлено в ES (2015 г.)

Обещание, которое вы говорите?

В точности то, что он означает, простыми словами, объект Promise представляет окончательное завершение (или отказ) асинхронной операции и ее результирующее значение.

var promise1 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve('foo');
  }, 300);
});
promise1.then(function(value) {
  console.log(value);
  // expected output: "foo"
});
console.log(promise1);
// expected output: [object Promise]

Более подробно объяснено в документации

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

Promise находится в одном из следующих состояний:

  • ожидает: начальное состояние, ни выполнено, ни отклонено.
  • выполнено: означает, что операция успешно завершена.
  • отклонено: это означает, что операция не удалась.

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

Поскольку методы Promise.prototype.then() и Promise.prototype.catch() возвращают обещания, их можно объединить в цепочку.

Асинхронный / Ожидание

Представленное в ES2017 объявление функции Async/Await определяет асинхронную функцию, которая возвращает объект AsyncFunction. Асинхронная функция - это функция, которая работает асинхронно через цикл событий, используя неявное обещание для возврата своего результата.

Но синтаксис и структура вашего кода с использованием асинхронных функций намного больше похожи на использование стандартных синхронных функций.

function resolveAfter2Seconds() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('resolved');
    }, 2000);
  });
}
async function asyncCall() {
  console.log('calling');
  var result = await resolveAfter2Seconds();
  console.log(result);
  // expected output: 'resolved'
}
asyncCall();

Более подробно объяснено в документации

Функция async может содержать выражение await, которое приостанавливает выполнение асинхронной функции и ожидает переданного разрешения Promise, а затем возобновляет выполнение asyncфункции и возвращает разрешенное значение.

Помните, что ключевое слово await допустимо только внутри async функций. Если вы используете его вне тела async функции, вы получите SyntaxError.

Попробуй поймать

Оператор try...catch отмечает блок операторов для попытки и указывает ответ на случай возникновения исключения.

function getProcessedData(url) {
  return downloadData(url) // returns a promise
    .catch(e => {
      return downloadFallbackData(url)  // returns a promise
    })
    .then(v => {
      return processDataInWorker(v); // returns a promise
    });
}

Это можно переписать как

async function getProcessedData(url) {
  let v;
  try {
    v = await downloadData(url); 
  } catch(e) {
    v = await downloadFallbackData(url);
  }
  return processDataInWorker(v);
}

Сноска: ES (2019) представила необязательную привязку catch, которая позволяет просто опускать переменную, включая круглые скобки после catch

Более подробно объяснено в документации

Оператор try состоит из блока try, который содержит один или несколько операторов. {} следует использовать всегда, даже для отдельных операторов. Должно присутствовать хотя бы одно предложение catch или предложение finally. Это дает нам три формы для оператора try:

  1. try...catch
  2. try...finally
  3. try...catch...finally

Предложение catch содержит инструкции, которые определяют, что делать, если в блоке try возникает исключение. То есть вы хотите, чтобы блок try успешно завершился, и если он не удастся, вы хотите передать управление блоку catch. Если какой-либо оператор в блоке try (или в функции, вызываемой из блока try) вызывает исключение, управление немедленно переходит к предложению catch. Если в блоке try не возникает исключения, предложение catch пропускается.

Предложение finally выполняется после блока try и предложений catch, но до операторов, следующих за оператором try. Он выполняется всегда, независимо от того, было выбрано исключение.

Вы можете вложить один или несколько операторов try. Если внутренний оператор try не имеет предложения catch, вводится предложение catch включающего оператора try.

В заключение

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