jQuery откладывает и обещает - .then () против .done ()

413

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

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

  • 13
    Обращаем ваше внимание, что JQuery 3.0, выпущенный в июне 2016 года, был первой версией, совместимой со спецификациями Promises / A + и ES2015 Promises. Реализация до этого имела несовместимость с обещаниями.
Теги:
promise
jquery-deferred

9 ответов

540
Лучший ответ

Обратные вызовы, привязанные к 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().

  • 49
    +1 - спасибо за ответ. Вы тот самый Джулиан Обур, который переписал AJAX для jQuery?
  • 146
    Не за что ... и да, я.
Показать ещё 4 комментария
362

Существует также разница в способе обработки результатов обработки (его называемая цепочка, 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
})
  • 113
    +1 для понятия, которое done , ничего не делает с результатом, где then изменяет результат. Огромный момент пропущен другими ИМО.
  • 9
    Вероятно, стоит упомянуть, к какой версии jQuery это применимо, так как поведение then изменилось в 1.8
Показать ещё 10 комментариев
53

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

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

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

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

  • 17
    Вы не упоминаете, что «then» создает цепочки вызовов. Смотрите ответ Lu4.
  • 0
    +1: ваш пост не дает ясного объяснения, как then себя вести, если fail предоставлен обратный вызов fail а именно - вообще не fail случай fail .
12

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);
}
  • 0
    Ваше сообщение не дает ясного объяснения того, как then себя вести, если fail предоставлен обратный вызов fail а именно - не fail случай fail
  • 0
    В случае сбоя возникает исключение, которое может быть перехвачено верхним уровнем программы. Вы также можете увидеть исключение в консоли JavaScript.
6

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

4

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

  • 0
    «then () всегда означает, что он будет вызван в любом случае» - неправда. then () никогда не вызывается в случае ошибки внутри Promise.
1

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

-3

это мой ответ.

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. это может помешать обратному аду.

-6

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

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

  • 6
    Внимание! Этот ответ будет правильным для нескольких реализаций обещаний, но не для jQuery, в котором .done() не имеет завершающей роли. В документации сказано: «Поскольку deferred.done () возвращает отложенный объект, другие методы отложенного объекта могут быть прикованы к этому, включая дополнительные методы .done ()». .fail() не упоминается, но, да, это тоже может быть связано.
  • 1
    Мой плохой, не проверял jQuery
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню