На самом деле есть довольно критическое различие, поскольку jQuery Deferreds предназначены для реализации Promises (а jQuery3.0 фактически пытается привести их в спецификацию).
Ключевое различие между готовым / затем заключается в том, что
.done()
ВСЕГДА возвращает те же значения Promise / wrapped, с которых он начинался, независимо от того, что вы делаете или что возвращаете.
.then()
всегда возвращает НОВОЕ Обещание, и вы отвечаете за контроль того, что это Обещание основано на том, какую функцию вы передали ему.
Переведенный из jQuery в собственные обещания ES2015, .done()
это своего рода реализация структуры "tap" вокруг функции в цепочке Promise, в которой он, если цепочка находится в состоянии "resol", передает значение функции .. но результат этой функции НЕ повлияет на саму цепочку.
const doneWrap = fn => x => { fn(x); return x };
Promise.resolve(5)
.then(doneWrap( x => x + 1))
.then(doneWrap(console.log.bind(console)));
$.Deferred().resolve(5)
.done(x => x + 1)
.done(console.log.bind(console));
Те, кто будет регистрировать 5, а не 6.
Обратите внимание, что я использовал done и doneWrap для ведения журнала, а не .then. Это потому, что функции console.log на самом деле ничего не возвращают. И что произойдет, если вы передадите .then функцию, которая ничего не возвращает?
Promise.resolve(5)
.then(doneWrap( x => x + 1))
.then(console.log.bind(console))
.then(console.log.bind(console));
Это войдет:
5
не определено
Что случилось? Когда я использовал .then и передал ему функцию, которая ничего не возвращала, это неявный результат был «undefined» ... который, конечно, возвратил Promise [undefined] для следующего метода then, который записал в журнал undefined. Таким образом, первоначальная ценность, с которой мы начали, была в основном потеряна.
.then()
по сути, это форма композиции функции: результат каждого шага используется в качестве аргумента для функции на следующем шаге. Вот почему .done лучше всего рассматривать как «нажатие» -> это на самом деле не часть композиции, а просто что-то, что пробуждает взгляд на значение на определенном шаге и запускает функцию с этим значением, но на самом деле не меняет композиция никак.
Это довольно фундаментальное различие, и, вероятно, есть веская причина, по которой нативные Promises не имеют реализованного метода .done. Нам не нужно разбираться, почему нет метода .fail, потому что он еще более сложен (а именно .fail / .catch НЕ являются зеркалами функций .done / .then -> в .catch, которые возвращают голые значения, не «остаться» отвергается, как те, которые были переданы. затем они решают!)