jQuery откладывает и обещает - .then () против .done () - PullRequest
445 голосов
/ 25 марта 2011

Я читал об отсрочках и обещаниях jQuery и не вижу разницы между использованием .then() & .done() для успешных обратных вызовов.Я знаю, Эрик Хиндс упоминает, что .done() и .success() соответствуют одной и той же функциональности, но я предполагаю, что .then() так же, как и все обратные вызовы, все запускаются после завершения успешной операции.

Может ли кто-нибудь объяснить мне правильное использование?

Ответы [ 8 ]

551 голосов
/ 25 марта 2011

Обратные вызовы, прикрепленные к 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's internal callback list
// (true, 56 and "omg" will be ignored)
promise.done( fn1, fn2, true, [ fn3, [ fn4, 56, fn5 ], "omg", fn6 ], fn7 );

То же самое относится к fail().

395 голосов
/ 29 марта 2013

Существует также различие в том, как обрабатываются возвращаемые результаты (это называется цепочкой, 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 вместо атомарного значения типа, внешнее обещание будет ждать, пока внутреннее обещание не разрешится:

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
})
52 голосов
/ 25 марта 2011

.done() имеет только один обратный вызов, и это успешный обратный вызов

.then() имеет как успешные, так и неудачные обратные вызовы

.fail() имеет только один сбойный обратный вызов

так что вам решать, что вы должны делать ... вас волнует, если это удастся или не получится?

13 голосов
/ 15 марта 2015

deferred.done ()

добавляет обработчики, которые будут вызываться только тогда, когда отложено разрешение .Вы можете добавить несколько обратных вызовов для вызова.

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 ()

добавляет обработчики квызывается , когда Отложено разрешено, отклонено или все еще выполняется .

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);
}
8 голосов
/ 22 декабря 2015

На самом деле есть довольно критическое различие, поскольку 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, которые возвращают голые значения, не «остаться» отвергается, как те, которые были переданы. затем они решают!)

4 голосов
/ 06 июля 2015

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как результат.

2 голосов
/ 08 декабря 2017

Существует очень простое ментальное отображение в ответе, которое было немного трудно найти в других ответах:

0 голосов
/ 30 октября 2014

.done() завершает цепочку обещаний, убеждаясь, что больше ничего не может присоединить к дальнейшим шагам. Это означает, что реализация обещания jQuery может выдать любое необработанное исключение, поскольку никто не может обработать его, используя .fail().

В практическом плане, если вы не планируете добавлять дополнительные шаги к обещанию, вы должны использовать .done(). Подробнее см. , почему нужно выполнять обещания

...