Понимание обещаний в Node.js


147

Из того, что я понял, есть три способа вызова асинхронного кода:

  1. События, например request.on("event", callback);
  2. Обратные вызовы, например fs.open(path, flags, mode, callback);
  3. обещания

Я нашел библиотеку обещаний узлов, но не получил ее.

Может ли кто-нибудь объяснить, что это за обещания и почему я должен их использовать?

Кроме того, почему он был удален из Node.js?


Эта статья объясняет это довольно хорошо. Когда дело доходит до реализации, используемой в node.js, взгляните на Futures
Шон Кинси,

Вот замечательная серия, которую я использовал для создания своего собственного класса обещаний: Давайте создадим платформу: обещания Вот видео о отложенном jQuery: blog.bigbinary.com/2011/09/03/jquery-deferred.html
Том Винтер,

Ответы:


91

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

Крутая вещь в обещаниях - вы можете объединить их в цепочки зависимостей (выполнять Promise C только после завершения Promise A и Promise B).

Удалив их из ядра node.js, он создал возможность создания модулей с различными реализациями обещаний, которые могут располагаться поверх ядра. Некоторые из них являются обещаниями узлов и фьючерсами .


10
@ weng Нет, это не так.
Иво Ветцель

98

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

  1. узел-обещание выглядит довольно мертвым для меня (последний коммит был около 1 года назад) и почти не содержит тестов.
  2. Модуль futures выглядит очень раздутым и плохо документирован (и я думаю, что соглашения об именах просто плохие)
  3. Наилучшим путем кажется использование структуры q , которая является активной и хорошо документированной.

9
Посмотрите также этот github.com/medikoo/deferred , Q - один из первых, и он определенно вдохновляет многие реализации, появившиеся впоследствии, но, к сожалению, он очень медленный и слишком «теоретический» в некоторых частях, он не очень хорошо работает с некоторыми сценарии реального мира
Мариуш Новак

Я бы проверить это видео на обещаниях одним из создателей RSVP.js youtube.com/...
runspired

23
Обновление 2014 года - bluebird , безусловно, самый быстрый и обладает лучшими возможностями отладки на сегодняшний день.
Бенджамин Грюнбаум

19

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

 var request = new Promise(function(resolve, reject) {
   //do an ajax call here. or a database request or whatever.
   //depending on its results, either call resolve(value) or reject(error)
   //where value is the thing which the operation's successful execution returns and
   //error is the thing which the operation's failure returns.
 });

 request.then(function successHandler(result) {
   //do something with the result
 }, function failureHandler(error) {
  //handle
 });

Спецификация обещаний гласит, что обещание

then

Метод должен возвращать новое обещание, которое выполняется, когда заданный обратный вызов successHandler или failHandler завершен. Это означает, что вы можете связывать воедино обещания, когда у вас есть набор асинхронных задач, которые необходимо выполнить, и вы можете быть уверены, что последовательность операций гарантирована, как если бы вы использовали обратные вызовы. Таким образом, вместо передачи обратного вызова внутри обратного вызова внутри обратного вызова, код с связанными обещаниями выглядит так:

var doStuff = firstAsyncFunction(url) {
                return new Promise(function(resolve, reject) {
                       $.ajax({
                        url: url,
                        success: function(data) {
                            resolve(data);
                        },
                        error: function(err) {
                             reject(err); 
                        } 
                  });
               };
doStuff
  .then(secondAsyncFunction) //returns a promise
  .then(thirdAsyncFunction); //returns a promise

Чтобы узнать больше об обещаниях и о том, почему они очень крутые, загляните в блог Доменика: http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/


12

Это новое руководство по обещаниям от автора PouchDB , вероятно, лучшее, что я когда-либо видел. Он мудро охватывает классические ошибки новичка, показывая вам правильные шаблоны использования и даже несколько анти-шаблонов, которые все еще широко используются - даже в других уроках !!

Наслаждайтесь!

PS Я не ответил на некоторые другие части этого вопроса, так как они были хорошо освещены другими.


Мое единственное извинение за это заставляет вас читать юмор в конце Продвинутой ошибки № 4.
Тони О'Хаган

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

Расширенная ошибка № 4 также может быть решена с помощью гораздо большего числа различных подходов, см. Как получить доступ к предыдущим результатам обещания в цепочке .then ()? (модель закрытия, которую они предлагают, кажется, не очень популярна).
Берги

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

7

У Майка Таулти есть серия видеороликов , каждое из которых длится менее десяти минут, и описывает, как работает библиотека WinJS Promise.

Эти видео довольно информативны, и Майку удается продемонстрировать всю мощь API Promise с помощью нескольких удачно выбранных примеров кода.

var twitterUrl = "http://search.twitter.com/search.json?q=windows";
var promise = WinJS.xhr({ url: twitterUrl });

 promise = promise.then(
     function (xhr) {
     },
     function (xhr) {
         // handle error
     });

Отношение к тому, как обрабатываются исключения, особенно хорошо.

Несмотря на ссылки на WinJs, это серия видеофильмов общего интереса, потому что API Promise в целом схожи во многих своих реализациях.

RSVP - это легкая реализация Promise, которая проходит тестовый набор Promise / A +. Мне очень нравится API, потому что он похож по стилю на интерфейс WinJS.

Обновление апрель 2014

Кстати, библиотека WinJS теперь с открытым исходным кодом .


1
+1. Это первый пример, который я видел, который имеет смысл для меня и интуитивно понятен в использовании. Каким-то образом мой мозг не может разобрать все deferredsи, resolveи deferred.promise.thenи предопределение promiseActionsв популярной документации библиотеки Q. Есть ли шанс, что вы знаете что-то такое простое для Node.js ?
Редсандро

1
@noel спасибо, что поделились ссылкой выше, это отличная вводная серия для обещаний, и я согласен, что особенности WinJS не имеют значения, так как общий подход / тема универсальны.
arcseldon

Хороший пример. Также я исправил вашу первую ссылку, которая была мертвой
stonedauwg

5

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

Библиотека bluebird реализует обещания и дает вам отличные длинные трассировки стека, очень быстро и предупреждает о необнаруженных ошибках. Он также работает быстрее и использует меньше памяти, чем другие библиотеки обещаний, согласно http://bluebirdjs.com/docs/benchmarks.html


4

Что именно обещание?

Обещание - это просто объект, представляющий результат асинхронной операции. Обещание может быть в любом из следующих 3 состояний:

pending :: Это начальное состояние, означает, что обещание не выполнено и не отклонено.

выполнено :: Это означает, что обещание выполнено, означает, что значение, представленное обещанием, готово к использованию.

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

  1. Функция executor :: executor определяет асинхронную операцию, которая должна быть выполнена и результат которой представлен обещанием. Он начинает выполнение, как только объект обещания инициализируется.

  2. resolv: resolv - это параметры, передаваемые функции executor, и в случае успешного выполнения executor это разрешение вызывается с передачей результата.

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

Поэтому всякий раз, когда мы создаем объект обещания, мы должны предоставлять Executor, Resolve и Reject.

Ссылка :: Обещания


0

Я также недавно смотрел на обещания в node.js. На сегодняшний день, кажется, путь when.js - путь из-за его скорости и использования ресурсов, но документация по q.js дала мне намного лучшее понимание. Так что используйте when.js, а не документы q.js, чтобы понять предмет.

Из файла q.js на github:

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


0

Объект Promise представляет завершение или сбой асинхронной операции.

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

1. Создание обещания:

Конструктор обещания принимает функцию, называемую исполнителем, которая имеет два параметра: разрешение и отклонение.

function example(){
   return new Promise (function(resolve , reject){   //return promise object
      if(success){
         resolve('success');  //onFullfiled
      }else{
         reject('error');     //onRejected
      }
   })
}

2. Обработка обещаний:

Объект Promise имеет 3 метода для обработки объектов обещаний: -

1.Promise.prototype.catch (onRejected)

2.Promise.prototype.then (onFullfiled)

3.Promise.prototype.finally (onFullfiled, onRejected)

example.then((data) =>{
  //handles resolved data
  console.log(data); //prints success     
}).catch((err) => {
  //handles rejected error 
  console.log(err);  //prints error
})
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.