Я читал об отложенных и обещанных jQuery и не вижу разницы между использованием .then()
и .done()
для успешных обратных вызовов. Я знаю, что Эрик Хиндс упоминает, что .done()
и .success()
отображаются на одну и ту же функциональность, но я предполагаю, что это так .then()
как все обратные вызовы вызываются при завершении успешной операции.
Может кто-нибудь, пожалуйста, просветите меня для правильного использования?
Обратные вызовы, привязанные к done()
, будут запущены, когда отложен запрос. Обратные вызовы, привязанные к fail()
, будут запущены, когда отложенные отклоняются.
До jQuery 1.8, then()
был просто синтаксическим сахаром:
promise.then( doneCallback, failCallback )
// was equivalent to
promise.done( doneCallback ).fail( failCallback )
Начиная с версии 1.8, then()
является псевдонимом для pipe()
и возвращает новое обещание, см. здесь для получения дополнительной информации о pipe()
.
success()
и error()
доступны только для объекта jqXHR
, возвращаемого вызовом ajax()
. Это простые псевдонимы для done()
и fail()
соответственно:
jqXHR.done === jqXHR.success
jqXHR.fail === jqXHR.error
Кроме того, done()
не ограничивается одним обратным вызовом и отфильтровывает не-функции (хотя в версии 1.8 есть ошибка со строками, которая должна быть исправлена в 1.8.1):
// this will add fn1 to 7 to the deferred internal callback list
// (true, 56 and "omg" will be ignored)
promise.done( fn1, fn2, true, [ fn3, [ fn4, 56, fn5 ], "omg", fn6 ], fn7 );
То же самое для fail()
.
Существует также разница в способе обработки результатов обработки (его называемая цепочка, done
не цепочка, а then
вызывает цепочки вызовов)
promise.then(function (x) { // Suppose promise returns "abc"
console.log(x);
return 123;
}).then(function (x){
console.log(x);
}).then(function (x){
console.log(x)
})
Следующие результаты будут регистрироваться:
abc
123
undefined
Пока
promise.done(function (x) { // Suppose promise returns "abc"
console.log(x);
return 123;
}).done(function (x){
console.log(x);
}).done(function (x){
console.log(x)
})
получит следующее:
abc
abc
abc
---------- Обновление:
Btw. Я забыл упомянуть, если вы вернете обещание вместо значения атомного типа, внешнее обещание будет ждать, пока не будет разрешено внутреннее обещание:
promise.then(function (x) { // Suppose promise returns "abc"
console.log(x);
return $http.get('/some/data').then(function (result) {
console.log(result); // suppose result === "xyz"
return result;
});
}).then(function (result){
console.log(result); // result === xyz
}).then(function (und){
console.log(und) // und === undefined, because of absence of return statement in above then
})
таким образом становится очень просто составлять параллельные или последовательные асинхронные операции, такие как:
// Parallel http requests
promise.then(function (x) { // Suppose promise returns "abc"
console.log(x);
var promise1 = $http.get('/some/data?value=xyz').then(function (result) {
console.log(result); // suppose result === "xyz"
return result;
});
var promise2 = $http.get('/some/data?value=uvm').then(function (result) {
console.log(result); // suppose result === "uvm"
return result;
});
return promise1.then(function (result1) {
return promise2.then(function (result2) {
return { result1: result1, result2: result2; }
});
});
}).then(function (result){
console.log(result); // result === { result1: 'xyz', result2: 'uvm' }
}).then(function (und){
console.log(und) // und === undefined, because of absence of return statement in above then
})
Вышеприведенный код выдает два HTTP-запроса параллельно, тем самым делая запросы завершенными раньше, а ниже эти HTTP-запросы запускаются последовательно, таким образом уменьшая нагрузку на сервер
// Sequential http requests
promise.then(function (x) { // Suppose promise returns "abc"
console.log(x);
return $http.get('/some/data?value=xyz').then(function (result1) {
console.log(result1); // suppose result1 === "xyz"
return $http.get('/some/data?value=uvm').then(function (result2) {
console.log(result2); // suppose result2 === "uvm"
return { result1: result1, result2: result2; };
});
});
}).then(function (result){
console.log(result); // result === { result1: 'xyz', result2: 'uvm' }
}).then(function (und){
console.log(und) // und === undefined, because of absence of return statement in above then
})
done
, ничего не делает с результатом, где then
изменяет результат. Огромный момент пропущен другими ИМО.
then
изменилось в 1.8
.done()
имеет только один обратный вызов и это обратный вызов успеха
.then()
имеет как успешные, так и отказоустойчивые обратные вызовы
.fail()
имеет только один отказоустойчивый вызов
так что вам решать, что вы должны делать... вам все равно, удастся ли ему или если он не работает?
then
себя вести, если fail
предоставлен обратный вызов fail
а именно - вообще не fail
случай fail
.
добавляет обработчики, которые будут называться , только когда Deferred разрешена. Вы можете добавить несколько обратных вызовов для вызова.
var url = 'http://jsonplaceholder.typicode.com/posts/1';
$.ajax(url).done(doneCallback);
function doneCallback(result) {
console.log('Result 1 ' + result);
}
Вы также можете написать выше, например,
function ajaxCall() {
var url = 'http://jsonplaceholder.typicode.com/posts/1';
return $.ajax(url);
}
$.when(ajaxCall()).then(doneCallback, failCallback);
добавляет обработчики, которые будут называться , когда Deferred разрешается, отклоняется или все еще выполняется.
var url = 'http://jsonplaceholder.typicode.com/posts/1';
$.ajax(url).then(doneCallback, failCallback);
function doneCallback(result) {
console.log('Result ' + result);
}
function failCallback(result) {
console.log('Result ' + result);
}
then
себя вести, если fail
предоставлен обратный вызов fail
а именно - не fail
случай fail
На самом деле существует довольно критическая разница, поскольку jQuery Deferreds предназначается для реализации Promises (и jQuery3.0 на самом деле пытается привести их в спецификацию).
Ключевое различие между сделанным/тогда заключается в том, что
.done()
ALWAYS возвращает те же самые значения Promise/wrapped, с которых оно начиналось, независимо от того, что вы делаете или что вы возвращаете..then()
всегда возвращает NEW Promise, и вы отвечаете за контроль над тем, что это обещание основано на том, что передала функция, которую вы передали.Переведенный из jQuery в родной ES2015 Promises, .done()
похож на реализацию структуры "касания" вокруг функции в цепочке Promise, поскольку она будет, если цепочка находится в состоянии "разрешения", передайте значение функции... но результат этой функции НЕ будет влиять на цепочку.
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));
Это будут как log 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));
Это будет log:
5
undefined
Что случилось? Когда я использовал .then и передал ему функцию, которая ничего не возвращала, это неявный результат был "undefined"... который, конечно же, возвратил Promise [ undefined] к следующему методу, который зарегистрировал undefined. Итак, исходное значение, с которого мы начали, в основном было потеряно.
.then()
- это, по сути, форма функционального состава: результат каждого шага используется в качестве аргумента для функции на следующем шаге. Вот почему лучше всего подумать о "постукивании" → это не на самом деле часть композиции, а просто что-то, что подкрадывается к значению на определенном шаге и запускает функцию при этом значении, но фактически не изменяет композиция в любом случае.
Это довольно фундаментальное различие, и, вероятно, это хорошая причина, почему native Promises не имеет .done-метода, реализованного самостоятельно. Нам не нужно разбираться в том, почему нет метода .fail, потому что это еще сложнее (а именно .fail/.catch НЕ являются зеркалами .done/.then- > функций в .catch, которые возвращают голые значения, не "остаться" отвергнутым, как те, которые были переданы. Затем они решаются!)
then()
всегда означает, что он будет вызван в любом случае. Но передача параметров различна в разных версиях jQuery.
До jQuery 1.8, then()
равно done().fail()
. И все функции обратного вызова имеют одинаковые параметры.
Но с jQuery 1.8, then()
возвращает новое обещание, и если оно возвращает значение, оно будет передано в следующую функцию обратного вызова.
Посмотрите следующий пример:
var defer = jQuery.Deferred();
defer.done(function(a, b){
return a + b;
}).done(function( result ) {
console.log("result = " + result);
}).then(function( a, b ) {
return a + b;
}).done(function( result ) {
console.log("result = " + result);
}).then(function( a, b ) {
return a + b;
}).done(function( result ) {
console.log("result = " + result);
});
defer.resolve( 3, 4 );
До jQuery 1.8 ответ должен быть
result = 3
result = 3
result = 3
Все result
принимают 3. И функция then()
всегда передает один и тот же отложенный объект следующей функции.
Но с jQuery 1.8 результат должен быть:
result = 3
result = 7
result = NaN
Поскольку первая функция then()
возвращает новое обещание, а значение 7 (и это единственный параметр, который будет передан) передается следующему done()
, поэтому вторая done()
записывает result = 7
. Второй then()
принимает значение 7 как значение a
и принимает undefined
как значение b
, поэтому второй then()
возвращает новое обещание с параметром NaN, а последний done()
печатает NaN как результат.
В ответах есть очень простое ментальное отображение, которое было немного сложно найти в других ответах:
done
реализует tap
, как в bluebird Promises
then
реализует then
как в ES6 Promises
это мой ответ.
var deff = $.Deferred();
deff.then(function(){
alert('ok');
var deff = $.Deferred();
setTimeout(function(){
deff.resolve()
}, 1000)
return deff;
}).then(function () {
alert('ok2')
})
deff.resolve()
Это уникальная функция then
. это может помешать обратному аду.
.done()
завершает цепочку обещаний, убедившись, что ничто другое не может приложить дальнейшие шаги. Это означает, что реализация обещания jQuery может вызывать любое необработанное исключение, поскольку никто не может справиться с ней с помощью .fail()
.
В практическом плане, если вы не планируете прилагать больше шагов к обещанию, вы должны использовать .done()
. Более подробно см. почему promises необходимо выполнить
.done()
не имеет завершающей роли. В документации сказано: «Поскольку deferred.done () возвращает отложенный объект, другие методы отложенного объекта могут быть прикованы к этому, включая дополнительные методы .done ()». .fail()
не упоминается, но, да, это тоже может быть связано.