私はjQueryの遅延とプロミスについて読んでいますが、コールバックの成功に.then()
&.done()
を使用することの違いがわかりません。私が知っているエリックHyndsがいることを言及.done()
して.success()
同じ機能にマッピングするが、私はそう推測している.then()
すべてのコールバックがすべて成功した操作の完了時に呼び出されるよう。
誰かが正しい使い方を教えてくれますか?
私はjQueryの遅延とプロミスについて読んでいますが、コールバックの成功に.then()
&.done()
を使用することの違いがわかりません。私が知っているエリックHyndsがいることを言及.done()
して.success()
同じ機能にマッピングするが、私はそう推測している.then()
すべてのコールバックがすべて成功した操作の完了時に呼び出されるよう。
誰かが正しい使い方を教えてくれますか?
回答:
にアタッチされたコールバック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()
のみ使用できます。これらは、それぞれの単純なエイリアスです。jqXHR
ajax()
done()
fail()
jqXHR.done === jqXHR.success
jqXHR.fail === jqXHR.error
また、done()
単一のコールバックに限定されず、非関数を除外します(1.8.1で修正されるバージョン1.8の文字列にはバグがあります)。
// 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()
。
then
新しい約束を返すことは私が欠けていた重要なことでした。のようなチェーン$.get(....).done(function(data1) { return $.get(...) }).done(function(data2) { ... })
がdata2
undefined で失敗する理由を理解できませんでした。私が変更done
したときはthen
、元のプロミスにハンドラーを追加するのではなく、プロミスを一緒にパイプ処理したかったので、うまくいきました。
done
またはを使用しますかthen
?どうして?
返される結果が処理される方法にも違いがあります(これはチェーンと呼ばれ、呼び出し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.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
})
done
結果をthen
変更する結果に対して何もしないという概念の+1 。他のイモが見逃した巨大なポイント。
then
1.8に変更
done
例のように動作します。1.8以上の動作を実現するには、1.8より前のバージョンに変更then
しpipe
てくださいthen
。
.done()
コールバックは1つだけあり、それは成功コールバックです
.then()
成功と失敗の両方のコールバックがあります
.fail()
失敗したコールバックは1つだけです
だから、あなたがしなければならないことはあなた次第です...それが成功するか失敗するかどうか気にしますか?
then()
大きく異なりdone()
ます。同様にthen()
、多くの場合、/覚えて知っている主なものよりも詳細は唯一のあなたのポイントコールバックの成功ではなく、あると呼ばれています。(jQuery 3.0より前の状態は言えません。)
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が解決、拒否、または進行中のときに呼び出されるハンドラーを追加します。
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);
}
then
、fail
コールバックが提供されていない場合の動作、つまりfail
ケースをまったくキャプチャしていない場合の動作が明確になっていません
jQueryのDeferredがPromiseの実装であることを意図している限り(そしてjQuery3.0は実際にそれらを仕様に組み込もうとしています)、実際にはかなり重大な違いがあります。
done / thenの主な違いは、
.done()
何をするか、何を返すかに関係なく、常に、最初と同じPromise /ラップされた値を返します。 .then()
常に新しいPromiseが返され、渡された関数が返したものに基づいてその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));
それらは両方とも6ではなく5を記録します。
.thenではなく、doneとdoneWrapを使用してログを記録したことに注意してください。これは、console.log関数が実際には何も返さないためです。そして、何も返さない関数を.thenに渡すとどうなりますか?
Promise.resolve(5)
.then(doneWrap( x => x + 1))
.then(console.log.bind(console))
.then(console.log.bind(console));
それはログに記録します:
5
未定義
どうした?.thenを使用して何も返さない関数を渡した場合、その暗黙の結果は「未定義」でした...もちろん、Promise [undefined]を次のthenメソッドに返し、未定義のログを記録しました。したがって、私たちが始めた当初の価値は基本的に失われました。
.then()
基本的には、関数構成の形式です。各ステップの結果は、次のステップの関数の引数として使用されます。そのため、.doneは「タップ」と考えるのが最適です->実際にはコンポジションの一部ではなく、特定のステップで値を調べ、その値で関数を実行するだけで、実際には変更しません。なんとなく構成。
これはかなり根本的な違いです。ネイティブのPromiseに.doneメソッドが実装されていないのには、おそらくそれなりの理由があります。.failメソッドが存在しない理由を説明する必要はありません。これはさらに複雑なためです(つまり、.fail / .catchは.done / .thenのミラーではないため、裸の値を返す.catchの関数ではありません。 「滞在」は、.thenに渡されたものと同様に拒否され、解決します!)
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
が3をとります。then()
関数は常に同じ遅延オブジェクトを次の関数に渡します。
しかし、jQuery 1.8以降、結果は次のようになります。
result = 3
result = 7
result = NaN
最初のthen()
関数は新しいpromiseを返し、値7(これは渡される唯一のパラメーターです)が次のdone()
に渡されるため、2番目のdone()
書き込みresult = 7
です。2番目then()
はの値として7をa
取りundefined
、の値として取るb
ので、2番目then()
はパラメーターNaNを使用して新しいプロミスを返し、最後done()
は結果としてNaNを出力します。
jQuery.Deferred()
が複数の値を受け取ることができる興味深い側面です.then()
。それは最初の値に適切に渡されます。— 少し奇妙ですが...次のように.then()
はできません。(選択されたインターフェース経由return
で返すことができる値は1つだけです。)JavascriptのネイティブPromise
はそれを行いません。(正直に言うと、より一貫性があります。)
他の回答では見つけるのが少し難しかった非常にシンプルなメンタルマッピングがあります。
done
ブルーバードプロミスのtap
ように実装します
then
ES6 Promiseのthen
ように実装します
.then()
これらはの欠点です .done()
resolve()
呼び出し(すべての.done()
ハンドラーは同期的に実行されます)resolve()
登録された.done()
ハンドラーから例外を受け取る可能性があります(!).done()
延期されたハーフキルの例外:
.done()
ハンドラは黙ってスキップされます私はそれを一時的に考え.then(oneArgOnly)
、常に必要です.catch()
:例外は黙って無視されますが、それはもはや真実ではないので、unhandledrejection
イベントが未処理のログに記録します.then()
(デフォルトとして)コンソール上の例外を。とてもリーズナブル!使用する理由は.done()
まったく残っていません。
次のコードスニペットはそれを明らかにします:
.done()
ハンドラは、次の時点で同期的に呼び出されますresolve()
.done()
影響を与えるresolve()
呼び出し元の
例外resolve()
.done()
解決からの約束を破ります
.then()
これらの問題はありません
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>
done
以前の完了に例外がある場合は実行されないというあなたの言っていることがわかります。しかし、なぜそれが黙って無視されるのでしょうか、つまり例外が発生したので、なぜ黙っていますか。2)Deferred
オブジェクトのAPIが非常に不十分であるため、オブジェクトを軽んじています。複雑すぎてわかりにくい。ここでのコードは、あなたの要点を証明するのにも役立ちませんし、証明しようとしていることに対して、必要以上に複雑すぎます。3)done
インデックス2、4、6が2番目の前に実行されるのはthen
なぜですか?
.then()
例外が発生するかどうかにかかわらず、それらのハンドラで例外がすべて呼び出されます。しかし、追加/残りの.done()
休憩。
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()コールバックが常に非同期で呼び出されることです。以前は、解決または拒否された.then()コールバックがDeferredに追加された場合、コールバックはすぐに同期的に実行されました。
.done()
Promiseチェーンを終了し、他に何も追加できないことを確認します。これは、jQuery promise実装が未処理の例外をスローする可能性があることを意味し.fail()
ます。
実際には、promiseにさらにステップを追加する予定がない場合は、を使用する必要があります.done()
。詳細については、約束をする必要がある理由をご覧ください
.done()
ますが、終了の役割がないjQueryには当てはまりません。ドキュメントには、「deferred.done()は遅延オブジェクトを返すため、追加の.done()メソッドを含め、遅延オブジェクトの他のメソッドをこのオブジェクトにチェーンすることができます」と記載されています。.fail()
言及されていませんが、はい、それは連鎖する可能性もあります。