Каковы различия между отложенным, обещанием и будущим в JavaScript?
Каковы различия между отсрочкой, обещаниями и фьючерсами?
Есть ли общепринятая теория за всеми этими тремя?
5 ответов
В свете явной неприязни к тому, как я пытался ответить на вопрос ОП. Буквальный ответ: обещание - это что-то общее с другими объектами, в то время как отложенное должно быть приватным. Прежде всего, отложенное (которое обычно расширяет 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.");
});
});
Извиняюсь за полупсевдокод, но я надеюсь, что это прояснит основную идею. По сути, возвращая стандартизированное обещание, вы можете обойти это обещание, тем самым обеспечивая более четкую группировку.
Эти ответы, в том числе выбранный ответ, хороши для концептуального представления обещаний, но в них отсутствует конкретика того, какие именно различия существуют в терминологии, которая возникает при использовании библиотек, реализующих их (и есть важные различия).
Поскольку это все еще развивающаяся спецификация, в настоящее время ответом является попытка изучить как ссылки (например, википедию), так и реализации (например, jQuery):
Отложено: Никогда не описывается в популярных ссылках, 1 2 3 4, но обычно используется реализациями как арбитр разрешения обещания (реализации
resolve
а такжеreject
). 5 6 7Иногда отсрочки также являются обещаниями
then
), 5 6 в других случаях считается более чистым иметь Deferred, способный только к разрешению, и принуждать пользователя к доступу к обещанию использованияthen
, 7Обещание: наиболее всеобъемлющее слово для обсуждаемой стратегии.
Прокси-объект, хранящий результат целевой функции, синхронность которой мы бы хотели абстрагировать, плюс выставление
then
функция, принимающая другую целевую функцию и возвращающая новое обещание. 2Пример из CommonJS:
> asyncComputeTheAnswerToEverything() .then(addTwo) .then(printResult); 44
Всегда описывается в популярных ссылках, хотя никогда не указывается, на кого ложится ответственность. 1 2 3 4
Всегда присутствует в популярных реализациях, и никогда не дает разрешения разрешения. 5 6 7
Будущее: казалось бы, устарелый термин, встречающийся в некоторых популярных ссылках 1 и, по крайней мере, в одной популярной реализации 8, но, по-видимому, постепенно исключаемый из обсуждения в пользу термина "обещание" 3 и не всегда упоминаемый в популярных введениях к теме. 9
Однако, по крайней мере, одна библиотека использует термин в общем для абстрагирования синхронности и обработки ошибок, не предоставляя при этом
then
функциональность. 10 Неясно, было ли намеренным избегать использования термина "обещание", но, вероятно, это хороший выбор, поскольку обещания строятся вокруг "выплачиваемых". 2
Рекомендации
- Википедия об обещаниях и фьючерсах
- Обещания /A+ spec
- Стандарт DOM на обещания
- DOM Стандартные Обещания Spec WIP
- DOJO Toolkit Deferreds
- jQuery Deferreds
- Q
- FutureJS
- Функциональный раздел Javascript на Promises
- Фьючерсы на интеграционное тестирование AngularJS
Разное потенциально запутанные вещи
Разница между Обещаниями / A и Обещаниями / A +
(TL; DR, Promises / A + в основном устраняет неясности в Promises/A)
То, что действительно заставило все это щелкнуть для меня, было этим представлением Домеником Дениколой.
В 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" с асинхронным кодом - это круто.
Если вы собираетесь использовать Обещания (вы должны попробовать их со своим собственным кодом!), Используйте вопрос Криса Ковала. Версия jQuery - это просто некий агрегатор обратного вызова для написания более чистого кода jQuery, но он упускает суть.
Что касается будущего, я понятия не имею, я не видел этого ни в одном API.
Изменить: выступление Доменика Дениколы на YouTube по обещаниям из комментария Farm ниже.
Цитата из Майкла Джексона (да, Майкла Джексона) из видео:
Я хочу, чтобы вы запомнили эту фразу: обещание - это асинхронная ценность.
Это превосходное описание: обещание похоже на переменную из будущего - первоклассную ссылку на что-то, что в какой-то момент будет (или произойдет).
Обещание представляет собой прокси для значения, которое не обязательно известно при создании обещания. Это позволяет связать обработчики с конечным значением успеха или причиной сбоя асинхронного действия. Это позволяет асинхронным методам возвращать значения, такие как синхронные методы: вместо конечного значения асинхронный метод возвращает обещание иметь значение в какой-то момент в будущем.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
deferred.promise()
Метод позволяет асинхронной функции предотвращать вмешательство другого кода в ход выполнения или состояние его внутреннего запроса. Обещание предоставляет только отложенные методы, необходимые для присоединения дополнительных обработчиков или определения состояния (затем выполнено, сбой, всегда, конвейер, прогресс, состояние и обещание), но не те, которые изменяют состояние (разрешить, отклонить, уведомить, resolWith, отклонить и уведомить).
Если цель указана, deferred.promise()
прикрепит к нему методы, а затем вернет этот объект, а не создаст новый. Это может быть полезно, чтобы прикрепить поведение Promise к объекту, который уже существует.
Если вы создаете Отложенное, сохраните ссылку на Отложенное, чтобы в какой-то момент его можно было разрешить или отклонить. Возвращайте только объект Promise через deferred.promise(), чтобы другой код мог регистрировать обратные вызовы или проверять текущее состояние.
Просто мы можем сказать, что Обещание представляет значение, которое еще не известно, тогда как Отложенное представляет работу, которая еще не завершена.
promise
представляет значение, которое еще не известноdeferred
представляет работу, которая еще не закончена
Обещание является заполнителем для результата, который изначально неизвестен, а отложенное представляет вычисление, которое приводит к значению.
Ссылка