Які відмінності між відкладеним, обіцяним та майбутнім у JavaScript?


300

Які відмінності між відстрочкою, обіцянками та майбутніми?
Чи існує загально затверджена теорія за всіма цими трьома?


11
Я не думаю, що це має нічого спільного з jQuery ...
BoltClock

11
Варто прочитати це: msdn.microsoft.com/en-us/scriptjunkie/gg723713
jfriend00

8
Я сам їх не використовував, але ось досить хороший вступ у wikipedia en.wikipedia.org/wiki/Futures_and_promises . Хоча я не повністю розумію справу використання належним чином. У мові, керованій подією async, як JavaScript. На перший погляд я не бачу, що вони пропонують за зворотній зв'язок, окрім, можливо, чистішого api. Мені б подобалося, якби хтось міг навести приклад використання випадків і показати, як ці поняття застосовуються, і чому зворотні виклики будуть неефективним рішенням @duri це не має нічого спільного з jQuery. Чи можна видалити тег jQuery
AshHeskes

2
@ jfriend00 чудове посилання, ймовірно, слід обробити відповідь.
fncomp

@ jfriend00 нове посилання - msdn.microsoft.com/en-us/magazine/gg723713.aspx
c69

Відповіді:


97

У світлі явної неприязні до того, як я намагався відповісти на питання ОП. Буквальна відповідь полягає в тому, що обіцянка - це щось спільне з іншими об'єктами, тоді як відкладене слід залишати приватним. Перш за все, відстрочка (яка, як правило, поширює обіцянку) може вирішити себе, тоді як обіцянка цього не зможе зробити.

Якщо вас цікавлять деталі, вивчіть Обіцянки / A + .


Наскільки я знаю, всеохоплююча мета - поліпшити чіткість і послабити зв'язок через стандартизований інтерфейс. Дивіться запропоновані читання від @ jfriend00:

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

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

Дійсно, порівняйте чисту форму зворотного виклику щось робити після завантаження CodeMirror в режимі JS асинхронно (вибачте, я не використовував jQuery деякий час ):

/* assume getScript has signature like: function (path, callback, context) 
   and listens to onload && onreadystatechange */
$(function () {
   getScript('path/to/CodeMirror', getJSMode);

   // onreadystate is not reliable for callback args.
   function getJSMode() {
       getScript('path/to/CodeMirror/mode/javascript/javascript.js', 
           ourAwesomeScript);
   };

   function ourAwesomeScript() {
       console.log("CodeMirror is awesome, but I'm too impatient.");
   };
});

До версії сформульованої обіцянки (знову ж таки, вибачте, я не в курсі jQuery):

/* Assume getScript returns a promise object */
$(function () {
   $.when(
       getScript('path/to/CodeMirror'),
       getScript('path/to/CodeMirror/mode/javascript/javascript.js')
   ).then(function () {
       console.log("CodeMirror is awesome, but I'm too impatient.");
   });
});

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


10
Хоча ця відповідь може бути корисною, вона фактично не стосується питання: так звані відстрочки є або ф'ючерсами, або обіцянками, залежно від реалізації.
awdz9nld

@ MartinKällman Ви маєте рацію! Я не переглядав це деякий час і трохи навчився. Я опублікую окрему відповідь нижче, але залиште це, оскільки люди, здається, отримали користь із прикладу використання.
fncomp

@ MartinKällman, розглядав можливість написати нову відповідь. Однак я думаю, що ОП насправді хотіла знати, що таке обіцянки та відстрочка. Відповідь на його актуальне запитання буде, приблизно, "відкладені можуть вирішити власне". AFAIK, теорія за обіцянками і відстрочками походить від [Функціонального Реактивного Програмування | haskell.org/haskellwiki/Functional_Reactive_Programming] , що є технікою вирівнювання зворотних викликів . "
fncomp

2
Це абсолютно неправильно, і ваші приклади так само легко зробити із зворотними дзвінками. Обіцяння стосуються не агрегації зворотного виклику та роз'єднання, а надання DSL для запису коду асинхронізації, як написано код синхронізації. Тим більше fn(callback, errback)не є більш щільно пов'язаним або менш корисним ніж fn().then(callback, errback)- але це неправильний спосіб використання обіцянок у будь-якому випадку. Я особливо ненавиджу $.whenприклад культового вантажу - немає абсолютно жодної причини, щоб у вас не було $.whenфункції, яка працювала з зворотними викликами.
Есаїлія

Це не відповідає на питання, хоча +1, що я можу знати, що таке пекло зворотного дзвінка.
Бходжендра Рауніяр

146

Ці відповіді, включаючи обрану відповідь, корисні для введення обіцянок концептуально, але не мають конкретики, які саме відмінності є у термінології, що виникає при використанні бібліотек, що їх реалізують (і є важливі відмінності).

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

  • Відкладено : Ніколи не описано в популярних посиланнях, 1 2 3 4, але зазвичай використовується реалізаціями як арбітр вирішення обіцянок (впровадження та ). 5 6 7 resolvereject

    Іноді відстрочки також є обіцянками (реалізацією then), 5 6 інших разів вважається більш чистою можливість мати відкладений лише здатність до вирішення та змушувати користувача отримувати доступ до обіцянки щодо використання . 7 then

  • Обіцянка : Найповажніше слово для обговорюваної стратегії.

    Проксі-об'єкт, що зберігає результат цільової функції, синхронність якої ми хотіли б абстрагувати, плюс викрити thenфункцію, яка приймає іншу цільову функцію і повертає нову обіцянку. 2

    Приклад з CommonJS :

    > asyncComputeTheAnswerToEverything()
        .then(addTwo)
        .then(printResult);
    44

     

    Завжди описується в популярних посиланнях, хоча ніколи не вказується, на чию відповідальність попадає відповідальність. 1 2 3 4

    Завжди присутній у популярних реалізаціях і ніколи не надає можливості роздільної здатності. 5 6 7

  • Майбутнє : здавалося б, застарілий термін, який зустрічається в деяких популярних посиланнях 1 і, принаймні, в одній популярній реалізації, 8, але, здавалося б, припиняється з обговорення, віддаючи перевагу терміну «обіцянка» 3 і не завжди згадується в популярних вступках до цієї теми. 9

    Однак принаймні одна бібліотека використовує цей термін загалом для абстрагування синхронності та керування помилками, не надаючи при цьому thenфункціоналу. 10 Незрозуміло, якщо уникнення терміну «обіцянка» було навмисним, але, ймовірно, вдалим вибором, оскільки обіцянки будуються навколо «пані». 2

Список літератури

  1. Вікіпедія про обіцянки та майбутнє
  2. Обіцянки / спец
  3. Стандарт DOM щодо обіцянок
  4. Стандарт DOM обіцяє специфіку WIP
  5. Відкладений інструментарій DOJO
  6. Відкладені jQuery
  7. Q
  8. FutureJS
  9. Функціональний розділ Javascript на Обіцяннях
  10. Майбутні в інтеграційних тестах AngularJS

Різне потенційно заплутує речі


5
Щоб додати трохи більше роз’яснень щодо терміна «Майбутнє» - ф'ючерси мають довгу історію для багатьох мов програмування, що починаються з середини 80-х. І цей термін все ще широко використовується, зокрема щодо СВМ. JavaScript, схоже, вирішив використовувати термін "Обіцяти", щоб означати щось подібне до того, що Java означає "Майбутнє". Scala відокремлює одне і те ж поняття на "Майбутнє" та "Обіцяння", щоб посилатися на "читати" і ручку "писати", що програмісти JavaScript називають Обіцянням.
Хізер Міллер

1
І звичайно Microsoft повинна була придумати свій термін для цього, тому в C # їх називаютьTask
BlueRaja - Danny Pflughoeft

72

Що насправді змусило мене натиснути це презентація Доменіка Денікола.

У сутичці github він дав опис, який мені найбільше подобається, це дуже стисло:

Сенс обіцянок полягає у тому, щоб повернути нам функціональну композицію та помилки, що виникають у асинхронному світі.

Іншими словами, обіцянки - це спосіб, який дозволяє нам писати асинхронний код, який майже так само просто записати, як ніби він був синхронним .

Розглянемо цей приклад із обіцянками:

getTweetsFor("domenic") // promise-returning async function
    .then(function (tweets) {
        var shortUrls = parseTweetsForUrls(tweets);
        var mostRecentShortUrl = shortUrls[0];
        return expandUrlUsingTwitterApi(mostRecentShortUrl); // promise-returning async function
    })
    .then(doHttpRequest) // promise-returning async function
    .then(
        function (responseBody) {
            console.log("Most recent link text:", responseBody);
        },
        function (error) {
            console.error("Error with the twitterverse:", error);
        }
    );

Це працює так, ніби ви писали цей синхронний код:

try {
    var tweets = getTweetsFor("domenic"); // blocking
    var shortUrls = parseTweetsForUrls(tweets);
    var mostRecentShortUrl = shortUrls[0];
    var responseBody = doHttpRequest(expandUrlUsingTwitterApi(mostRecentShortUrl)); // blocking x 2
    console.log("Most recent link text:", responseBody);
} catch (error) {
    console.error("Error with the twitterverse: ", error);
}

(Якщо це все ще звучить складно, дивіться цю презентацію!)

Щодо відкладеного, це шлях .resolve()або .reject()обіцянки. У специфіці Обіцянки / Б вона називається .defer(). У jQuery це $.Deferred().

Зауважте, що, наскільки я знаю, реалізація Promise в jQuery порушена (див. Цю суть), принаймні, як у jQuery 1.8.2.
Він нібито реалізує обіцянки / Thenable , але ви не отримаєте правильного поводження з помилками, у тому сенсі, що вся функція "асинхронна спроба / зловити" не працюватиме. Шкода, адже мати "спробувати / зловити" з асинхронним кодом надзвичайно здорово.

Якщо ви збираєтеся використовувати Promises (ви повинні спробувати їх з власним кодом!), Використовуйте Kris Коваль в Q . Версія jQuery - це лише якийсь агрегатор зворотних викликів для написання більш чистого коду jQuery, але пропускає суть.

Щодо майбутнього, то я не маю уявлення, я не бачив цього в жодному API.

Редагувати: Домонік Денікола на youtube розмовляє на Обіцянки з коментаря @Farm нижче.

Цитата Майкла Джексона (так, Майкл Джексон ) з відео:

Я хочу, щоб ти запалив цю думку в думці: Обіцянка - це асинхронна цінність .

Це чудовий опис: обіцянка - це як змінна з майбутнього - першокласна посилання на щось, що в певний момент буде існувати (або відбуватиметься).


5
Велике пояснення ф'ючерсів (! В даний час здійснюється в DOM) членом основної команди W3 і Chrome можна знайти тут: xanthir.com/b4PY0
oligofren

1
@oligofren Дякую за посилання, що здається приємним! До речі, який таємничо дратує фавікон лол.
Каміло Мартін

1
Ця відповідь потребує набагато більше результатів. Він повинен бути проголосований вище, ніж прийнята відповідь ІМО.
Шев

1
Розмова на youtube Домені Денікола на Promises: youtube.com/watch?v=hf1T_AONQJU
Ферма

@Farm Чудово! Я додам це до відповіді.
Каміло Мартін

32

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

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

deferred.promise()Метод дозволяє асинхронна функції для запобігання іншого коду від втручання прогресу або статусом свого внутрішнього запиту. Обіця викриває лише методи відкладені, необхідні для приєднання додаткових обробників або визначення стану ( тоді, зроблено, не вдалося, завжди, передача, прогрес, стан і обіцянка ), але не ті, які змінюють стан ( вирішувати, відхиляти, повідомляти, вирішувати, відхилитиWith та notifyWith ).

Якщо ціль надана, deferred.promise()приєднає до неї методи, а потім поверне цей об'єкт, а не створює новий. Це може бути корисно для приєднання поведінки Обіцяння до об'єкта, який вже існує.

Якщо ви створюєте "Відкладений", зберігайте посилання на "Відкладений", щоб воно могло бути вирішено або відхилено в якийсь момент. Повертайте лише об’єкт Promise через deferred.promise (), щоб інший код міг реєструвати зворотні дзвінки або перевіряти поточний стан.

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


введіть тут опис зображення


1
плюс 1 для подання діаграми Бравісімо !! ^ _ ^
Ашок М.А.,

23
  • A promiseявляє собою значення, яке ще не відомо
  • А deferredпредставляє роботу, яка ще не закінчена

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

Довідково

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.