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

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

5 ответов


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

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

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


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

еще развивающаяся спецификация, ответ в настоящее время исходит из попытки исследовать обе ссылки (например,Википедия) и реализации (как jQuery):

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

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

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

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

    пример CommonJS:

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

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

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

  • будущее: казалось бы, устаревший термин, найденный в некоторых популярных ссылках 1 и хотя бы одна популярная реализация, 8 но, по-видимому, постепенно из обсуждения в пользу срок 'обещание' 3 и не всегда упоминается в популярных введениях к теме. 9

    однако, по крайней мере, одна библиотека использует термин в целом для абстрагирования синхронность и обработка ошибок, не предоставляя then функциональность. 10 Неясно, было ли намеренным избегать термина "обещание", но, вероятно, хороший выбор, так как обещания строятся вокруг 'thenables.' 2

ссылки

  1. Википедия о обещаниях и фьючерсах
  2. обещания / A+ spec
  3. стандарт DOM на обещаниях
  4. стандарт DOM обещает спецификацию WIP
  5. Dojo Toolkit Deferreds
  6. в jQuery Deferreds
  7. Q
  8. FutureJS
  9. функциональный раздел Javascript о обещаниях
  10. фьючерсы в интеграционном тестировании AngularJS

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


что действительно заставило все это щелкнуть для меня было презентации по Concha Denicola.

на 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() обещания. В Обещания / B spec, это называется .defer(). В jQuery, это $.Deferred().

обратите внимание, что как я знаю, реализация обещания в jQuery нарушена (см. эту суть), по крайней мере, с jQuery 1.8.2.
Он якобы реализует обещания/а thenables, но вы не получаете правильную обработку ошибок, в том смысле, что вся функциональность "async try/catch" не будет работать. Что жаль, потому что иметь "try/catch" с асинхронным кодом совершенно круто.

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

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

Edit: youtube разговор Доминика Дениколы о обещаниях С @Farmкомментарий ниже.

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

Я хочу, чтобы ты сожгла эту фразу в своем уме: обещание-это асинхронный стоимостью.


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

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

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

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

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

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


enter image description here


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

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

ссылка