Каковы различия между отложенным, обещанием и будущим в JavaScript?

300

Каковы различия между отсрочкой, обещаниями и фьючерсами?
Есть ли общепринятая теория за всеми этими тремя?

башня
источник
11
Я не думаю, что это имеет какое-либо отношение к jQuery ...
BoltClock
11
Стоит прочитать это: msdn.microsoft.com/en-us/scriptjunkie/gg723713
jfriend00
8
Я не использовал их сам, но вот довольно хорошее введение в Википедии en.wikipedia.org/wiki/Futures_and_promises . Хотя я не совсем правильно понимаю вариант использования. В асинхронном управляемом событиями языке, таком как javascript. На первый взгляд я не вижу, что они предлагают по сравнению с обратными вызовами, кроме, может быть, более чистого API. Я был бы рад, если бы кто-нибудь смог привести пример использования и показать, как применяются эти концепции и почему обратные вызовы были бы неэффективным решением. @ Duri это не имеет ничего общего с JQuery. Можно ли удалить тег jQuery, пожалуйста
AshHeskes,
2
@ Jfriend00 отличная ссылка, вероятно, должны быть обработаны в ответ.
fncomp
@ jfriend00 новая ссылка - msdn.microsoft.com/en-us/magazine/gg723713.aspx
c69

Ответы:

97

В свете явной неприязни к тому, как я пытался ответить на вопрос ОП. Буквальный ответ: обещание - это что-то общее с другими объектами, а отложенное должно быть приватным. Прежде всего, отложенное (которое обычно расширяет Promise) может разрешиться само собой, в то время как обещание может быть не в состоянии это сделать.

Если вас интересуют подробности, изучите Promises / A + .


Насколько я знаю, главная цель - улучшить четкость и ослабить связь через стандартизированный интерфейс. Смотрите рекомендуемое чтение от @ jfriend00:

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

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

Действительно, сравните чистую форму обратного вызова, что-то делать после асинхронной загрузки 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.");
   });
});

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

fncomp
источник
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функции, работающей с обратными вызовами.
Esailija
Это не отвечает на вопрос, хотя +1, что я мог бы знать, что такое адбэк обратного вызова.
Бходжандра Раунияр
146

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

Поскольку это все еще развивающаяся спецификация , в настоящее время ответом является попытка изучить как ссылки (например, википедию ), так и реализации (например, jQuery ):

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

    Иногда deferreds также являются обещаниями (реализация then), 5 6 в других случаях считается более чистым иметь Deferred, способный только к разрешению, и принуждать пользователя к доступу к обещанию для использования . 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. Обещания / A + spec
  3. Стандарт DOM на обещания
  4. DOM Стандартные Обещания Spec WIP
  5. DOJO Toolkit Deferreds
  6. jQuery Deferreds
  7. Q
  8. FutureJS
  9. Функциональный раздел Javascript на Promises
  10. Фьючерсы в AngularJS Интеграционное Тестирование

Разное потенциально запутанные вещи

Woahdae
источник
5
Чтобы добавить немного уточнения к термину «Будущее» - фьючерсы имеют долгую историю во многих языках программирования, начиная с середины 80-х годов. И этот термин все еще широко используется сегодня, в частности в JVM. Похоже, что JavaScript решил использовать термин «обещание» для обозначения чего-то похожего на то, что Java подразумевает под «будущим». Scala разделяет одну и ту же концепцию на «Future» и «Promise» для обозначения дескриптора «read» и дескриптора «write», который программисты JavaScript называют Promise.
Хизер Миллер
1
И, конечно, Microsoft должен был придумать свой собственный термин для этого, поэтому в C # они называютсяTask
BlueRaja - Дэнни Пфлугхофт
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);
}

(Если это все еще кажется сложным, посмотрите эту презентацию!)

Что касается Deferred, это способ .resolve()или .reject()обещания. В спецификации Promises / B это называется .defer(). В jQuery это так $.Deferred().

Обратите внимание, что, насколько мне известно, реализация Promise в jQuery не работает (см. Суть), по крайней мере, начиная с jQuery 1.8.2.
Предположительно, он реализует функции Promises / A thenables , но вы не получите правильной обработки ошибок, которую вы должны, в том смысле, что вся функциональность «асинхронная попытка / отлов» не будет работать. Что жаль, потому что иметь «try / catch» с асинхронным кодом - это круто.

Если вы собираетесь использовать Обещания (вы должны попробовать их со своим собственным кодом!), Используйте Q Криса Ковала . Версия jQuery - это просто агрегатор обратных вызовов для написания более чистого кода jQuery, но он упускает суть.

Что касается будущего, я понятия не имею, я не видел этого ни в одном API.

Изменить: выступление Доменика Дениколы на YouTube по обещаниям из комментария @Farm ниже.

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

Я хочу, чтобы вы запомнили эту фразу: обещание - это асинхронная ценность .

Это превосходное описание: обещание похоже на переменную из будущего - первоклассную ссылку на то, что в какой-то момент будет (или произойдет).

Камило Мартин
источник
5
Отличное объяснение Futures (теперь реализованное в DOM!) Членом основной команды W3 и Chrome можно найти здесь: xanthir.com/b4PY0
oligofren
1
@oligofren Спасибо за ссылку, это приятно! Кстати, что за таинственно раздражающий favicon LOL.
Камило Мартин
1
Этот ответ требует гораздо больше голосов. Следует проголосовать выше принятого ответа ИМО.
Chev
1
Выступление Доменика Дениколы на YouTube по обещаниям: youtube.com/watch?v=hf1T_AONQJU
Ферма
@ Ферма Отлично! Я добавлю это к ответу.
Камило Мартин
32

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

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

Этот deferred.promise()метод позволяет асинхронной функции предотвращать вмешательство другого кода в ход выполнения или состояние его внутреннего запроса. Обещание предоставляет только отложенные методы, необходимые для присоединения дополнительных обработчиков или определения состояния ( затем выполнено, сбой, всегда конвейер, прогресс, состояние и обещание ), но не те, которые изменяют состояние ( разрешение, отклонение, уведомление, resolWith, отклонить и уведомить ).

Если цель указана, deferred.promise()методы будут прикреплены к ней, а затем будут возвращать этот объект, а не создавать новый. Это может быть полезно для прикрепления поведения Promise к объекту, который уже существует.

Если вы создаете Отложенное, сохраните ссылку на Отложенное, чтобы в какой-то момент его можно было разрешить или отклонить. Возвращайте только объект Promise через deferred.promise (), чтобы другой код мог регистрировать обратные вызовы или проверять текущее состояние.

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


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

ИРШАД
источник
1
плюс 1 для представления диаграммы. Bravisimo !! ^ _ ^
Ашок М.А.
23
  • A promiseпредставляет значение, которое еще не известно
  • А deferredпредставляет работу, которая еще не закончена

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

Ссылка

mattLummus
источник