Розуміння обіцянок у 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 було те, що вони були випромінювачами, які могли випромінювати лише дві події: успіх і помилка.

Класна річ у обіцянках - ви можете об'єднати їх у ланцюги залежностей (виконайте Обіцяння С лише тоді, коли Обіцянка А та Обіцянка Б завершені).

Видаляючи їх з основного node.js, він створив можливість нарощування модулів з різними реалізаціями обіцянок, які можуть сидіти в верхній частині ядра. Деякі з них - це перспективні вузли та ф'ючерси .


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

98

Оскільки це питання все ще має багато поглядів (як у мене), я хотів зазначити, що:

  1. Вузол-обіцянка виглядає для мене досить мертвим (останній вчинок був близько 1 року тому) і майже не містить тестів.
  2. Модуль ф'ючерсів виглядає для мене дуже роздутим і погано задокументований (і я вважаю, що конвенції про іменування просто погані)
  3. Найкращим способом пройти здається рамка q , яка є активною і добре зафіксованою.

9
Перевірте також цей github.com/medikoo/deferred , Q - один із перших, і це, безумовно, натхнення для багатьох реалізацій, які з'явилися згодом, але, на жаль, у деяких частинах це дуже повільно і занадто "теоретично", з деякими не грає. реальні сценарії світу
Маріуш Новак

Я перевірив би це відео на обіцянках одного з творців RSVP.js youtube.com/…
runpired

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

метод повинен повернути нову обіцянку, яка буде виконана, коли даний успіхHandler або callHandler завершено. Це означає, що ви можете об'єднати обіцянки, коли у вас є набір асинхронних завдань, які потрібно виконати, і бути впевненим, що послідовність операцій гарантована так само, як якщо б ви використовували зворотні дзвінки. Таким чином, замість передачі зворотного дзвінка всередині зворотного дзвінка всередині зворотного дзвінка код з ланцюжковими обіцянками виглядає так:

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

Щоб дізнатися більше про обіцянки та чому вони надзвичайно круті, перегляньте блог Domenic: http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/


12

Цей новий підручник про Обіцянки від автора PouchDB - це, мабуть, найкраще, що я бачив де-небудь. Він розумно висвітлює класичні помилки новичка, показуючи правильні схеми використання та навіть декілька анти-шаблонів, які все ще часто використовуються - навіть в інших навчальних посібниках !!

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

PS Я не відповів на деякі інші частини цього питання, оскільки їх добре висвітлювали інші.


Моє єдине вибачення за це - змушує вас читати гумор наприкінці помилки №4.
Тоні О’Хаган

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

Розширена помилка №4 також може бути вирішена за допомогою набагато більшої кількості різних підходів, див. Як я отримую доступ до результатів попередньої обіцянки в ланцюгу athen ()? (модель закриття, яку вони пропонують, здається, не дуже популярна).
Бергі

Я думаю, що ця відповідь, що стосується лише посилання, повинна бути краще коментарем. Будь ласка, вкажіть тут хоча б основні моменти цієї статті у своїй відповіді.
Бергі

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

Ще одна перевага обіцянок полягає в тому, що поводження з помилками та викидання та вилучення винятків набагато краще, ніж намагання впоратися з зворотними дзвінками.

Бібліотека блакитних птахів реалізує обіцянки та дає вам великі довгі сліди стека, дуже швидко та попереджає про невдалі помилки. Він також швидший і використовує менше пам'яті, ніж інші бібліотеки з обіцянками, згідно з http://bluebirdjs.com/docs/benchmarks.html


4

Що саме таке Обіцянка?

Обіцянка - це просто об'єкт, який представляє результат операції з асинхронізацією. Обіцяння може бути в будь-якому з наступних 3 штатів:

очікується :: Це початковий стан, означає, що обіцянка не виконується і не відкидається.

Виконано :: Це означає, що обіцянка виконана, означає, що значення, представлене обіцянкою, готове до використання.

відхилено :: Це означає, що операції провалилися, а значить, не можуть виконати обіцянку. Крім штатів, є три важливі сутності, пов'язані з обіцянками, які нам дійсно потрібно зрозуміти

  1. Функція виконавця :: виконавець визначає операцію асинхронізації, яку потрібно виконати і результат якої представлений обіцянкою. Він починає виконання, як тільки об'єкт обіцянки ініціалізується.

  2. разрешить: разрешить - параметр, переданий функції виконавця, і якщо виконавець працює успішно, це рішення називається передачею результату.

  3. reject :: reject - це ще один параметр, переданий функції виконавця, і він використовується, коли функція виконавця виходить з ладу. Причина відмови може бути передана до відхилення.

Тому щоразу, коли ми створюємо об'єкт обіцянки, ми повинні надавати Виконавцю, Розв’язувати та Відхиляти.

Довідка :: Обіцянки


0

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

З q.js readme на github:

Якщо функція не може повернути значення або викинути виняток без блокування, вона може повернути обіцянку. Обіцянка - це об'єкт, який представляє повернене значення або викинутий виняток, який функція в кінцевому підсумку може забезпечити. Обіцянку також можна використовувати як проксі-сервер для віддаленого об'єкта для подолання затримки.


0

Обіцяючий об'єкт являє собою завершення або збій асинхронної операції.

Тож для виконання обіцянки вам потрібні дві частини: -

1. Створення обіцянки:

Конструктор обіцянок приймає функцію, яку називають виконавцем, яка має 2 параметри вирішення та відхилення.

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

2. Поводження з обіцяною:

Обіцяючий об'єкт має 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.