JQuery отложенные и promises -.then() vs .done()
Я читал об отложенных и обещанных jQuery и не вижу разницы между использованием .then()
и .done()
для успешных обратных вызовов. Я знаю, что Эрик Хиндс упоминает, что .done()
и .success()
отображаются на одну и ту же функциональность, но я предполагаю, что это так .then()
как все обратные вызовы вызываются при завершении успешной операции.
Может кто-нибудь, пожалуйста, просветите меня для правильного использования?
Ответы
Ответ 1
Обратные вызовы, привязанные к 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()
.
Ответ 2
Существует также разница в способе обработки результатов обработки (его называемая цепочка, 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
})
Ответ 3
.done()
имеет только один обратный вызов и это обратный вызов успеха
.then()
имеет как успешные, так и отказоустойчивые обратные вызовы
.fail()
имеет только один отказоустойчивый вызов
так что вам решать, что вы должны делать... вам все равно, удастся ли ему или если он не работает?
Ответ 4
deferred.done()
добавляет обработчики, которые будут называться , только когда 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.then()
добавляет обработчики, которые будут называться , когда 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);
}
Ответ 5
На самом деле существует довольно критическая разница, поскольку 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, которые возвращают голые значения, не "остаться" отвергнутым, как те, которые были переданы. Затем они решаются!)
Ответ 6
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 как результат.
Ответ 7
В ответах есть очень простое ментальное отображение, которое было немного сложно найти в других ответах:
Ответ 8
это мой ответ.
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
. это может помешать обратному аду.
Ответ 9
.done()
завершает цепочку обещаний, убедившись, что ничто другое не может приложить дальнейшие шаги. Это означает, что реализация обещания jQuery может вызывать любое необработанное исключение, поскольку никто не может справиться с ней с помощью .fail()
.
В практическом плане, если вы не планируете прилагать больше шагов к обещанию, вы должны использовать .done()
. Более подробно см. почему promises необходимо выполнить