498

私はjQueryの延期と約束について読んでいますが、コールバックを成功させるために.then()&を使用することの違いがわかりません。Eric Hyndsがそれについて言及し、同じ機能にマップしていること.done()は知っていますが、操作が成功するとすべてのコールバックが呼び出されるため、そうだと思います。.done().success().then()

誰かが私に正しい使い方を教えてもらえますか?

4

11 に答える 11

591

にアタッチされたコールバックdone()は、遅延が解決されたときに発生します。にアタッチされたコールバックfail()は、遅延が拒否されたときに発生します。

jQuery 1.8より前then()は、単なる構文糖衣でした。

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

1.8の時点で、then()はのエイリアスでpipe()あり、新しいpromiseを返します。の詳細については、ここを参照してくださいpipe()

success()との呼び出しによって返されerror()たオブジェクトでのみ使用できます。これらはそれぞれとの単純なエイリアスです。jqXHRajax()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()

于 2011-03-25T18:55:38.270 に答える
429

戻り結果の処理方法にも違いがあります(チェーンと呼ばれ、コールチェーンを生成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

- - - - - アップデート:

ところで。アトミックタイプの値の代わりにPromiseを返す場合、外側のpromiseは内側の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
})

上記のコードは2つの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
})
于 2013-03-28T23:35:15.430 に答える
60

.done()コールバックは1つだけで、成功コールバックです

.then()成功と失敗の両方のコールバックがあります

.fail()失敗したコールバックは1つだけです

だからあなたがしなければならないことはあなた次第です...それが成功するか失敗するかを気にしますか?

于 2011-03-25T18:11:44.233 に答える
16

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);
}
于 2015-03-15T03:42:50.710 に答える
11

jQueryのDeferredsがPromisesの実装であることが意図されている限り(そしてjQuery3.0は実際にそれらを仕様に取り入れようとする限り)、実際にはかなり重大な違いがあります。

done / thenの主な違いは、

  • .done()何をするか、何を返すかに関係なく、常に最初に使用したものと同じPromise/wrapped値を返します。
  • .then()常に新しいPromiseを返します。あなたは、渡した関数が返したものに基づいて、そのPromiseが何であるかを制御する責任があります。

jQueryからネイティブES2015Promisesに変換されるの.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));

それらは両方とも6ではなく5を記録します。

.thenではなくdoneとdoneWrapを使用してロギングを行ったことに注意してください。これは、console.log関数が実際には何も返さないためです。そして、何も返さない関数を渡すとどうなりますか?

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は「タップ」として最もよく考えられています->これは実際には構成の一部ではなく、特定のステップで値を確認し、その値で関数を実行するものですが、実際には変更されませんとにかく構成。

これはかなり根本的な違いであり、ネイティブPromisesに.doneメソッドが実装されていないのにはおそらく十分な理由があります。.failメソッドがない理由を理解する必要はありません。これはさらに複雑だからです(つまり、.fail/.catchは.done/.thenのミラーではありません->裸の値を返す.catchの関数は、渡されたもののように拒否された「滞在」。その後、解決します!)

于 2015-12-22T19:02:15.507 に答える
7

then()常に、どのような場合でも呼び出されることを意味します。ただし、渡されるパラメーターは、jQueryのバージョンによって異なります。

jQuery 1.8より前は、にthen()等しいdone().fail()。また、すべてのコールバック関数は同じパラメーターを共有します。

ただし、jQuery 1.8以降then()、新しいpromiseが返され、値が返された場合は、次のコールバック関数に渡されます。

次の例を見てみましょう。

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そして、then()関数は常に同じ遅延オブジェクトを次の関数に渡します。

ただし、jQuery 1.8の時点では、結果は次のようになります。

result = 3
result = 7
result = NaN

最初のthen()関数は新しいpromiseを返し、値7(およびこれが渡される唯一のパラメーター)が次の関数に渡されるdone()ため、2番目のdone()書き込みはresult = 7です。2番目then()はの値として7を取り、の値としてa取るので、2番目はパラメーターNaNを持つ新しいpromiseを返し、最後はその結果としてNaNを出力します。undefinedbthen()done()

于 2015-07-06T13:28:08.747 に答える
4

使用するだけ.then()

これらはの欠点です.done()

  • 連鎖することはできません
  • ブロックresolve()呼び出し(すべての.done()ハンドラーは同期して実行されます)
  • resolve().done()登録されたハンドラーから例外が発生する可能性があります(!)
  • 半分の例外.done()-延期された人を殺します:
    • それ以降の.done()ハンドラーはサイレントにスキップされます

一時的に、例外が黙って無視されないように.then(oneArgOnly)する必要があると思い.catch()ましたが、それはもう真実ではありません。unhandledrejectionイベントは、未処理.then()の例外をコンソールに記録します(デフォルトとして)。とてもリーズナブル!使用する理由は.done()まったくありません。

証拠

次のコードスニペットは、次のことを示しています。

  • すべての.done()ハンドラーは、次の時点で同期と呼ばれます。resolve()
    • 1、3、5、7として記録
    • スクリプトが最下位に落ちる前にログに記録されます
  • .done()インフルエンスのresolve()呼び出し元 の例外
    • キャッチアラウンド経由でログに記録resolve()
  • .done()例外はさらなる解決 からの約束を破る
    • 8と10はログに記録されません!
  • .then()これらの問題はありません
    • スレッドがアイドル状態になった後、2、4、6、9、11としてログに記録されます
    • (スニペット環境にはないunhandledrejectionようです)

ところで、からの例外を.done()適切にキャッチすることはできません。の同期パターンのため、エラーは(ライブラリコードである可能性があります!).done()の時点でスローされるか、延期がすでに解決されている場合は原因をアタッチする呼び出しでスローされます。.resolve().done()

console.log('Start of script.');
let deferred = $.Deferred();
// deferred.resolve('Redemption.');
deferred.fail(() => console.log('fail()'));
deferred.catch(()=> console.log('catch()'));
deferred.done(() => console.log('1-done()'));
deferred.then(() => console.log('2-then()'));
deferred.done(() => console.log('3-done()'));
deferred.then(() =>{console.log('4-then()-throw');
    throw 'thrown from 4-then()';});
deferred.done(() => console.log('5-done()'));
deferred.then(() => console.log('6-then()'));
deferred.done(() =>{console.log('7-done()-throw');
    throw 'thrown from 7-done()';});
deferred.done(() => console.log('8-done()'));
deferred.then(() => console.log('9-then()'));

console.log('Resolving.');
try {
    deferred.resolve('Solution.');
} catch(e) {
    console.log(`Caught exception from handler
        in resolve():`, e);
}
deferred.done(() => console.log('10-done()'));
deferred.then(() => console.log('11-then()'));
console.log('End of script.');
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh"
crossorigin="anonymous"
></script>

于 2020-04-01T04:40:51.260 に答える
3

他の回答では見つけるのが少し難しい応答として、非常に単純なメンタルマッピングがあります。

于 2017-12-08T16:24:37.137 に答える
3

jQuery 3.0の時点で、予期しない動作を簡単に引き起こす可能性があり、以前の回答では言及されていない、もう1つの重要な違いがあります。

次のコードを検討してください。

let d = $.Deferred();
d.done(() => console.log('then'));
d.resolve();
console.log('now');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>

これは出力します:

then
now

ここで、まったく同じスニペットで次のようにdone()置き換えます。then()

var d = $.Deferred();
d.then(() => console.log('then'));
d.resolve();
console.log('now');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>

出力は次のようになります。

now
then

したがって、すぐに解決された遅延の場合、に渡された関数done()は常に同期的に呼び出されますが、に渡された引数then()は非同期で呼び出されます。

これは、アップグレードガイドで説明されているように、両方のコールバックが同期的に呼び出される以前のjQueryバージョンとは異なります。

Promises / A +コンプライアンスに必要なもう1つの動作変更は、Deferred .then()コールバックが常に非同期で呼び出されることです。以前は、すでに解決または拒否されたDeferredに.then()コールバックが追加された場合、コールバックは即座に同期して実行されていました。

于 2019-12-04T14:58:20.420 に答える
1

上記の回答に加えて:

.thenの真の力は、ajax呼び出しを流暢な方法で連鎖させ、コールバック地獄を回避する可能性です。

例えば:

$.getJSON( 'dataservice/General', {action:'getSessionUser'} )
    .then( function( user ) {
        console.log( user );
        return $.getJSON( 'dataservice/Address', {action:'getFirstAddress'} );
    })
    .then( function( address ) {
        console.log( address );
    })

ここで、2番目の.thenは、返された$.getJSONの後に続きます

于 2021-02-17T19:12:18.567 に答える
-4

.done()約束チェーンを終了し、他に何も追加のステップを添付できないことを確認します。これは、jQueryのpromise実装は、を使用して処理できないため、未処理の例外をスローできることを意味し.fail()ます。

実際には、promiseにさらにステップを追加する予定がない場合は、を使用する必要があります.done()。詳細については、約束を行う必要がある理由をご覧ください

于 2014-10-30T14:27:40.637 に答える