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

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

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

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

function fetchData(url, callback) {
  const request = new XMLHttpRequest();
  request.open("GET", url);

  request.onload = function() {
    if (request.status === 200) {
      callback(null, JSON.parse(request.responseText));
    } else {
      callback(request.status);
    }
  };

  request.onerror = function() {
    callback("Network Error");
  };

  request.send();
}

fetchData("https://jsonplaceholder.typicode.com/users/1", function(error, data) {
  if (error) {
    console.error(error);
  } else {
    console.log(data);
  }
});

В этом примере мы определяем функцию fetchData, которая принимает функции url и callback в качестве аргументов. Эта функция создает новый объект XMLHttpRequest, открывает запрос GET к предоставленному URL-адресу, а затем определяет два обработчика событий: один для onload и один для onerror.

Обработчик события onload проверяет, равен ли код состояния ответа 200, и если это так, он анализирует текст ответа как JSON и передает его функции обратного вызова в качестве второго аргумента. Если код состояния не равен 200, он вызывает функцию обратного вызова с кодом состояния в качестве первого аргумента.

Обработчик события onerror просто вызывает функцию обратного вызова со строкой «Ошибка сети».

Затем мы вызываем fetchData с URL-адресом и функцией обратного вызова, которая записывает данные в консоль, если ошибок нет, или записывает ошибку в консоль, если есть ошибка.

Обещания в NodeJS

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

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

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

function fetchData(url) {
  return new Promise(function(resolve, reject) {
    const request = new XMLHttpRequest();
    request.open("GET", url);

    request.onload = function() {
      if (request.status === 200) {
        resolve(JSON.parse(request.responseText));
      } else {
        reject(request.status);
      }
    };

    request.onerror = function() {
      reject("Network Error");
    };

    request.send();
  });
}

fetchData("https://jsonplaceholder.typicode.com/users/1")
  .then(function(data) {
    console.log(data);
  })
  .catch(function(error) {
    console.error(error);
  });

В этом примере мы определяем функцию fetchData, которая принимает url и возвращает новый объект Promise. Внутри конструктора Promise мы создаем новый объект XMLHttpRequest и определяем обработчики событий onload и onerror, как и раньше.

Если обработчик события onload выполнен успешно, он вызывает функцию resolve с проанализированными данными JSON в качестве аргумента. В случае неудачи вызывается функция reject с кодом состояния в качестве аргумента.

Если вызывается обработчик события onerror, он просто вызывает функцию reject со строкой «Ошибка сети».

Затем мы вызываем fetchData с URL-адресом и используем метод then для присоединения функции обратного вызова, которая записывает данные в консоль. Мы также используем метод catch для присоединения функции обратного вызова, которая регистрирует ошибку в консоли, если она возникает.

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

Заключение

В заключение, как обратные вызовы, так и обещания являются важными инструментами для обработки асинхронного кода в NodeJS. Однако промисы предлагают несколько преимуществ по сравнению с обратными вызовами, включая лучшую читабельность, более простую обработку ошибок и возможность использовать async/await. Если вы создаете новое приложение NodeJS или хотите улучшить производительность и читабельность существующего приложения, стоит подумать об использовании промисов вместо обратных вызовов.

Если хотите узнать больше об обещаниях, загляните в следующий блог.

Глубокое погружение в промисы в JavaScript: понимание промисов, цепочки, обработка ошибок и лучшие практики

Купи мне кофе