На самом деле есть довольно критическое различие, поскольку jQuery's 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 лучше всего рассматривать как «нажатие» -> это на самом деле не часть композиции, а просто то, что пробуждает взгляд на значение на определенном шаге и запускает функцию с этим значением, но фактически не меняет композиция никак.
Это довольно фундаментальное различие, и, вероятно, есть веская причина, по которой нативные обещания не имеют реализованного метода .done. Нам не нужно разбираться, почему нет метода .fail, потому что он еще более сложен (а именно .fail / .catch НЕ являются зеркалами функций .done / .then -> в .catch, которые возвращают голые значения, не «остаться» отвергается, как те, которые были переданы. затем они решают!)