jQuery odrocza i obiecuje -.then () vs. done()

Czytałem o jQuery deferreds i promises i nie widzę różnicy między używaniem .then() & .done() dla udanych połączeń zwrotnych. Wiem Eric Hynds wspomina, że .done() i .success() mapują tę samą funkcjonalność, ale zgaduję, że tak jest .then(), ponieważ wszystkie wywołania zwrotne są wywoływane po zakończeniu udanej operacji.

Czy ktoś może oświecić mnie do prawidłowego użycia?

Wielkie dzięki

Author: Bergi, 2011-03-25

8 answers

Wywołania zwrotne dołączone do done() zostaną wywołane po rozwiązaniu odroczenia. Wywołania zwrotne dołączone do fail() zostaną wywołane, gdy odroczenie zostanie odrzucone.

Przed jQuery 1.8, then() był tylko cukrem składniowym:

promise.then( doneCallback, failCallback )
// was equivalent to
promise.done( doneCallback ).fail( failCallback )

Od 1.8, then() jest aliasem dla pipe() i zwraca nową obietnicę, zobacz tutaj aby uzyskać więcej informacji na temat pipe().

success() i {[10] } są dostępne tylko na obiekcie jqXHR zwracanym przez wywołanie do ajax(). Są to proste aliasy dla done() i fail() odpowiednio:

jqXHR.done === jqXHR.success
jqXHR.fail === jqXHR.error

Również, done() nie jest ograniczone do pojedynczego wywołania zwrotnego i odfiltruje Nie-funkcje (choć jest błąd z ciągami w wersji 1.8, który powinien być naprawiony w 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 );

To samo dotyczy fail().

 522
Author: Julian Aubourg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:27

Istnieje również różnica w sposobie przetwarzania wyników zwracanych (wywołanie łańcuchowe, done nie powoduje łańcucha, podczas gdy then wytwarza łańcuchy wywołania)

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

Następujące wyniki zostaną zalogowane:

abc
123
undefined

While

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

Otrzyma:

abc
abc
abc

---------- Aktualizacja:

Btw. Zapomniałem wspomnieć, że jeśli zwrócisz obietnicę zamiast wartości typu atomowego, zewnętrzna obietnica będzie czekać, aż wewnętrzna obietnica się rozwiąże: {]}

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

W ten sposób bardzo proste staje się tworzenie równoległych lub sekwencyjnych operacji asynchronicznych, takich jak:

// 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
})

Powyższy kod wysyła dwa żądania http równolegle, co sprawia, że żądania kończą się szybciej, podczas gdy poniżej tych żądań http są uruchamiane sekwencyjnie, zmniejszając obciążenie serwera

// 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
})
 367
Author: Lu4,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-29 08:59:39

.done() ma tylko jeden callback i jest to callback sukcesu

.then() ma zarówno sukces, jak i niepowodzenie wywołania zwrotnego

.fail() posiada tylko jeden Fail callback

Więc to od Ciebie zależy, co musisz zrobić... obchodzi cię, czy się uda, czy nie?
 49
Author: Marino Šimić,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-27 18:10:11

Odroczone.done ()

Dodaje obsługę do wywołania tylko wtedy, gdy Deferred jest rozwiązany . Możesz dodać wiele wywołań zwrotnych do wywołania.

var url = 'http://jsonplaceholder.typicode.com/posts/1';
$.ajax(url).done(doneCallback);

function doneCallback(result) {
    console.log('Result 1 ' + result);
}

Możesz też napisać wyżej tak:

function ajaxCall() {
    var url = 'http://jsonplaceholder.typicode.com/posts/1';
    return $.ajax(url);
}

$.when(ajaxCall()).then(doneCallback, failCallback);

Odroczone.then ()

Dodaje procedury obsługi, które mają być wywołane gdy odroczenie zostanie rozwiązane, odrzucone lub nadal w toku .

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);
}
 12
Author: Nipuna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-15 03:42:50

W rzeczywistości istnieje dość krytyczna różnica, ponieważ odroczenia jQuery mają być implementacją obietnic (a jQuery3.0 próbuje wprowadzić je do specyfikacji).

Kluczową różnicą między done/then jest to, że

  • .done() zawsze zwraca te same wartości obietnicy/owinięte, od których się zaczęło, niezależnie od tego, co zrobisz lub co zwrócisz.
  • .then() zawsze zwraca nową obietnicę, a Ty jesteś odpowiedzialny za kontrolowanie tego, na czym ta obietnica jest oparta jaka funkcja, którą przekazałeś, powróciła.

Przetłumaczone z jQuery na natywne obietnice ES2015, .done() jest czymś w rodzaju implementacji struktury " tap " wokół funkcji w łańcuchu obietnic, ponieważ, jeśli łańcuch jest w stanie "resolve", przekazuje wartość do funkcji... ale wynik tej funkcji nie wpłynie na sam łańcuch.

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

Oba logują 5, Nie 6.

Zauważ, że używałem done I doneWrap do logowania, nie .więc. To dlatego, że konsola.funkcje dziennika niczego nie zwracają. I co się stanie ,jeśli zdasz.więc funkcja, która niczego nie zwraca?

Promise.resolve(5)
       .then(doneWrap( x => x + 1))
       .then(console.log.bind(console))
       .then(console.log.bind(console));

To się loguje:

5

Undefined

Co się stało? Kiedy używałem .następnie i przekazał mu funkcję, która nic nie zwraca, to wynik niejawny był "undefined"... co oczywiście zwróciło obietnicę [undefined] do następnej metody, która zapisała undefined. Więc pierwotna wartość, od której zaczęliśmy, to w zasadzie przegrałem.

.then() jest, w głębi serca, formą kompozycji funkcji: wynik każdego kroku jest używany jako argument funkcji w następnym kroku. Dlatego .done najlepiej traktować jako "tap" - > nie jest to w rzeczywistości część kompozycji, tylko coś, co przemyka spojrzenie na wartość na pewnym etapie i uruchamia funkcję o tej wartości, ale tak naprawdę nie zmienia kompozycji w żaden sposób.

Jest to dość zasadnicza różnica i prawdopodobnie jest dobry powód dlaczego rodzime obietnice nie mająmetoda done zaimplementowała się. Nie musimy się zastanawiać, dlaczego nie ma .metoda fail, bo to jeszcze bardziej skomplikowane (mianowicie,.fail/haczyk nie jest lustrem .zrobione/.następnie - > funkcje w .catch that return gołe wartości nie "pozostają" odrzucone jak te przekazywane do .wtedy się rozwiążą!)

 6
Author: Dtipson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-01 02:51:51

then() zawsze oznacza, że będzie nazywany w każdym przypadku. Ale parametry przekazywane są różne w różnych wersjach jQuery.

Przed jQuery 1.8, then() równa się done().fail(). Wszystkie funkcje wywołania zwrotnego mają te same parametry.

Ale od jQuery 1.8, then() zwraca nową obietnicę, a jeśli ma zwracaną wartość, zostanie przekazana do następnej funkcji zwrotnej.

Spójrzmy na następujący przykład:

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

Przed jQuery 1.8, odpowiedź powinna be

result = 3
result = 3
result = 3

Wszystkie result zajmuje 3. I then() funkcja zawsze przekazuje ten sam obiekt do następnej funkcji.

Ale od jQuery 1.8 wynik powinien być:

result = 3
result = 7
result = NaN

Ponieważ pierwsza then() funkcja zwraca nową obietnicę, a wartość 7 (i jest to jedyny parametr, który zostanie przekazany)jest przekazywana do następnej done(), więc druga done() zapisuje result = 7. Druga then() przyjmuje 7 jako wartość a i przyjmuje {[15] } jako wartość b, więc druga then() zwraca nową obietnicę z parametrem NaN, a ostatnia done() wyświetla NaN jako jej wynik.

 4
Author: JasmineOT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-06 13:35:44

Jest bardzo proste mapowanie umysłowe w odpowiedzi, które było nieco trudne do znalezienia w innych odpowiedziach:

  • done implementuje tap Jak w

  • then implementuje thenjak w ES6 obiecuje

 1
Author: B M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-08 16:24:37

.done() kończy łańcuch obietnic, upewniając się, że nic innego nie może dołączyć dalszych kroków. Oznacza to, że implementacja jQuery promise może wyrzucić dowolny nieobsługiwany wyjątek, ponieważ nikt nie może go obsłużyć za pomocą .fail().

W praktyce, jeśli nie planujesz dołączyć więcej kroków do obietnicy, powinieneś użyć .done(). Po więcej szczegółów zobacz Dlaczego obietnice muszą być wykonane

 -5
Author: gleb bahmutov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-30 14:27:40