Обещания в Node.js

Введение. JavaScript является однопоточным, что означает, что все, включая события, выполняется в одном потоке. Если поток не свободен, выполнение кода откладывается до тех пор, пока он не освободится. Это может стать узким местом для нашего приложения, поскольку действительно может вызвать серьезные проблемы с производительностью. Есть разные способы преодолеть это ограничение. В этой статье мы исследуем современный способ обработки асинхронных задач в JavaScript - Promises. Обратные вызовы и обратный вызов Ад, если вы JavaSc

Вступление

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

Есть разные способы преодолеть это ограничение. В этой статье мы исследуем современный способ обработки асинхронных задач в JavaScript - Promise s.

Обратные вызовы и обратный вызов Ад

Если вы разработчик JavaScript, вы, вероятно, слышали о обратных вызовах , если они не используются:

 function hello() { 
 console.log('Hello World!'); 
 } 
 
 setTimeout(hello, 5000); 

Этот код выполняет функцию setTimeout() , которая ожидает в течение определенного времени (в миллисекундах), переданного ему в качестве второго аргумента, 5000 . По прошествии времени только тогда он выполняет функцию hello , переданную ему в качестве первого параметра.

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

Допустим, мы отправили запрос в API, чтобы вернуть самые понравившиеся фотографии из нашей учетной записи. Скорее всего, нам придется дождаться ответа, поскольку API / служба может производить некоторые вычисления перед возвратом ответа.

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

До этого времени выполняется остальная часть кода, такая как представление сообщений и уведомлений.

Если вы когда-либо работали с обратными вызовами, есть шанс, что вы испытали ад обратных вызовов :

 doSomething(function(x) { 
 console.log(x); 
 doSomethingMore(x, function(y) { 
 console.log(y); 
 doRestOfTheThings(y, function(z) { 
 console.log(z); 
 }); 
 }); 
 }); 

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

Управление этими вложенными зависимостями может быстро выйти из-под контроля.

Мы можем избежать ада обратных вызовов и обрабатывать асинхронные вызовы с помощью Promise s.

Создание обещания

Promise s, как следует из названия, - это функция, «дающая слово», что значение будет возвращено позже. Это прокси для значения, которое может не быть возвращено, если функция, от которой мы ожидаем ответа, не доставит.

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

Чаще всего при кодировании мы будем использовать Promise а не создавать их. Именно библиотеки / фреймворки создают Promise для использования клиентами.

Тем не менее, хорошо понимать, что стоит за созданием Promise :

 let promise = new Promise(function(resolve, reject) { 
 // Some imaginary 2000 ms timeout simulating a db call 
 setTimeout(()=> { 
 if (/* if promise can be fulfilled */) { 
 resolve({msg: 'It works', data: 'some data'}); 
 } else { 
 // If promise can not be fulfilled due to some errors like network failure 
 reject(new Error({msg: 'It does not work'})); 
 } 
 }, 2000); 
 }); 

Конструктор обещания получает аргумент - обратный вызов. Обратный вызов может быть обычной функцией или функцией стрелки. Обратный вызов принимает два параметра - resolve и reject . Оба являются ссылками на функции. Обратный вызов также называется исполнителем.

Исполнитель запускается сразу после создания обещания. Обещание разрешается путем вызова resolve() если обещание выполнено, и отклоняется путем вызова reject() если оно не может быть выполнено.

Оба resolve() и reject() принимают один аргумент - boolean , string , number , array или object .

Потребление обещания

Скажем, через API мы запросили некоторые данные с сервера, и неизвестно, когда они будут возвращены - если они вообще будут возвращены. Это прекрасный пример того, как мы могли бы использовать Promise чтобы помочь нам.

Предполагая, что метод сервера, который обрабатывает наш вызов, возвращает Promise , мы можем использовать его:

 promise.then((result) => { 
 console.log("Success", result); 
 }).catch((error) => { 
 console.log("Error", error); 
 }) 

Как мы видим, мы связали два метода - then() и catch() . Это несколько из различных методов, предоставляемых объектом Promise

then() выполняется, когда все идет хорошо, т.е. обещание выполняется методом resolve() . И если обещание было отклонено, catch() с ошибкой, отправленной для reject .

Цепочка обещаний

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

Это приводит нас к аду обратных вызовов, которого можно легко избежать, связав несколько then() с одним Promise d:

 promise.then(function(result) { 
 // Register user 
 return {account: 'blahblahblah'}; 
 }).then(function(result) { 
 // Auto login 
 return {session: 'sjhgssgsg16775vhg765'}; 
 }).then(function(result) { 
 // Present WhatsNew and some options 
 return {whatsnew: {}, options: {}}; 
 }).then(function(result) { 
 // Remember the user Choices 
 return {msg: 'All done'}; 
 }); 

Как мы видим, результат передается через цепочку обработчиков then()

  • Первоначальный объект promise
  • Затем then() для регистрации пользователя
  • Возвращаемое значение передается следующему then() для автоматического входа пользователя.
  • ...и так далее

Кроме того, then(handler) может создавать и возвращать обещание.

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

 let promise = new Promise(function(resolve, reject) { 
 setTimeout(() => resolve({msg: 'To do some more job'}), 1000); 
 }); 
 
 promise.then(function(result) { 
 return {data: 'some data'}; 
 }); 
 
 promise.then(function(result) { 
 return {data: 'some other data'}; 
 }); 
 
 promise.then(function(result) { 
 return {data: 'some more data'}; 
 }); 

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

Таким образом, все обработчики получают один и тот же результат - результат этого обещания - {msg: 'To do some more job'} .

Заключение

Promise s, как следует из названия, - это функция, «дающая слово», что значение будет возвращено позже. Это прокси для значения, которое может не быть возвращено, если функция, от которой мы ожидаем ответа, не доставит.

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

Если вы работали с обратными вызовами, вы должны оценить чистую и ясную семантику Promise s.

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

comments powered by Disqus

Содержание