Каковы различия между отложенным, обещанием и будущим в JavaScript? - PullRequest
293 голосов
/ 23 июля 2011

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

Ответы [ 5 ]

143 голосов
/ 17 сентября 2013

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

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

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

    Иногда отсрочки также являются обещаниями (реализация then), 5 6 В других случаях более чистым считается наличие у Отложенного только способности с разрешением и принуждения пользователя к доступу к обещанию использовать then. 7

  • Обещание : наиболее всеобъемлющее слово для обсуждаемой стратегии.

    Прокси-объект, хранящий результат целевой функции, синхронность которой мы хотели бы абстрагировать, плюс предоставление then функции, принимающей другую целевую функцию и возвращающей новое обещание. 2

    Пример из CommonJS :

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

    Всегда описывается в популярных ссылках,хотя никогда не указывалось, на кого возлагается ответственность. 1 2 3 4

    Всегда присутствует в популярных реализациях и никогда не получает разрешение. способности 5 6 7

  • Future : на первый взгляд устарелотермин встречается в некоторых популярных ссылках 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

Разное, что может сбить с толку

96 голосов
/ 26 июля 2011

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

Если вас интересуют подробности, изучите Обещания / 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.");
   });
});

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

72 голосов
/ 23 ноября 2012

Что по-настоящему заставило меня задуматься, так это эта презентация от Доменика Дениколы.

В github gist он дал описание, которое мне нравится больше всего, оно очень лаконично:

Смысл обещаний состоит в том, чтобы вернуть нам функциональную композицию и всплывающую ошибку в асинхронном мире.

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

Рассмотрим этот пример с обещаниями:

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() обещаний. В спецификации Promises / B она называется .defer(). В jQuery это $.Deferred().

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

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

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

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

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

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

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

29 голосов
/ 03 февраля 2016

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

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

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

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

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

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


enter image description here

21 голосов
/ 24 сентября 2014
  • A promise представляет значение, которое еще не известно
  • A deferred представляет работу, которая еще не закончена

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

Ссылки

...