$.ajax() は、他の遅延関連メソッドが詰まったオブジェクトを返します。promise() について説明しましたが、then()、success()、error() などのメソッドも見つかります。ただし、完全な遅延オブジェクトにはアクセスできず、遅延オブジェクトの状態を確認するために使用できるのは、Promise、コールバック バインディング メソッド、および isRejected() メソッドと isResolved() メソッドのみです。オブジェクト全体を返さない場合は、処理をいじることが可能であり、おそらくプラグマティックに遅延を「解決」して、AJAX リクエストが完了する前にすべてのバインドされたコールバックを起動させる可能性があります。パラダイム全体を壊す可能性があるため、dfd.promise() のみを返します。
$.ajax() はオブジェクト (ネイティブ XMLHttpRequest のカプセル化である jqXHR) を返します。このオブジェクトには、promise()、then()、success() などの遅延関連関数が含まれています。 、error()、isRejected()、isResolved()。
しかし、そこには、resolve()、resolveWith()、reject()、rejectWith() 関数がなく、これらの関数は遅延オブジェクトのプロセスを変更するために使用されていることに気づきましたか。つまり、$.ajax() は
完全な遅延オブジェクトが返された場合、外部プログラムは任意に遅延オブジェクトのコールバック関数をトリガーできますが、AJAX リクエストが終了する前にコールバック関数 (解決) がトリガーされる可能性が非常に高くなります。 AJAX 自体のロジックに。
jqXHR がありません。
jqXHR.resolveWith = deferred.resolveWith;
次に、次のコードを実行します:
// $ .get、非同期 AJAX リクエスト
var req = $.get('./sample.txt').success(function (response) {
console.log('AJAX success');
} ).error(function () {
console.log('AJAX エラー');
});
req.resolve(); / AJAX コールバック関数をもう 1 つ追加します。AJAX はこの時点で終了しているか、まだ終了していない可能性があります
// $.ajax には遅延サポートが組み込まれているため、次のように記述できます
req.success (関数 (応答) {
console.log('AJAX success2');
});
console.log('END');このときの実行結果は、
AJAX success -> AJAX success2 -> END
つまり、実際の AJAX リクエストが終了する前に、成功コールバック関数がトリガーされてエラーが発生します。
これらすべてをより明確に確認するために、成功コールバック関数にいくつかの偽のパラメーターを手動で渡します。
コードをコピー
コードは次のとおりです。 // $.get、非同期 AJAX リクエスト var req = $.get('./sample.txt').success(function (応答) { console.log('AJAX 成功(' 応答 ')');
req.resolve('偽のデータ'); / 別の AJAX コールバック関数を追加します。AJAX はこの時点で終了しているか、まだ終了していない可能性があります
// $.ajax には遅延サポートが組み込まれているため、次のように記述できます
req.success(関数 (応答) {
console.log('AJAX success2(' 応答 ')')
console.log('END');
この時点での実行結果は次のとおりです:
AJAX success(Fake data) ->AJAX success2(Fake data) -> END
コード分析
jQuery コードに入る前に
deferred.promise() メソッドを使用すると、他のコードが内部リクエストの進行状況やステータスに干渉するのを防ぐことができます。Promise は、必要な Deferred メソッドのみを公開します。追加のハンドラーをアタッチしたり、状態を決定したり (then、done、fail、isResolved、isRejected) しますが、状態を変更するもの (resolve、reject、resolveWith、rejectWith) は使用しません。
Deferred を作成している場合は、そのままにしておきます。ある時点で解決または拒否できるようにするための Deferred への参照。 deferred.promise() 経由で Promise オブジェクトのみを返すため、他のコードがコールバックを登録したり、現在の状態を検査したりできます。
大まかに言えば、遅延。 .promise() は、他のコードが非同期タスクの内部フローを変更するのを防ぐために使用されます。 Promise オブジェクトは、コールバック関数と状態を検出する関数をパブリックに追加するだけで、状態を変更する関数は含まれません。
遅延オブジェクトを手動で作成する場合は、コールバック関数をトリガーするために状態を変更するために遅延オブジェクトへの参照を維持する必要があります。ただし、戻り値は deferred.promise() にする必要があります。これにより、外部プログラムはコールバック関数を追加したり状態を検出したりできますが、状態を変更することはできません。
この時点で、誰もが約束について明確に理解しているはずです。次の 2 つのコードを見てみましょう。これらはまったく同じ機能を実行します。
コードをコピー
コードは次のとおりです。 🎜>
function getData() {
return $.get('/foo/');
}
console.log('アニメーションと AJAX リクエストの両方が完了しました!');
});
コードをコピー
コードは次のとおりです。
function getData( ) {
return $.get('/foo/');
}
function showDiv() {
// 正しいコードです。これはお勧めできません。
return $.Deferred(function (dfd) { $('#foo').fadeIn(1000, dfd.resolve); }); $ .when(getData(), showDiv()).then(function (ajaxResult) { console.log('アニメーションと AJAX リクエストの両方が完了しました!');
}); 🎜>
上記の 2 つのコードは同じタスクを実行し、2 番目のコードの方が簡潔に見えますが、2 番目のコードは推奨されるアプローチではありません。
タスク (showDiv) 自体のステータスの変更はタスク内に保持される必要があり、外部に公開する必要がないため、読み取り専用の遅延オブジェクトを公開するだけで済みます。約束。
最後に、Deferred 関連のソース コードを見てみましょう。
//Promise 関連メソッドの配列
promiseMethods = "then doned failed isResolved isRejected Promise".split( " " ),
jQuery.extend(
// 完全な遅延オブジェクト (2 つのコールバック キューあり)
Deferred: function (func) {
var deferred = jQuery._Deferred(),
failDeferred = jQuery._Deferred(),
promise;
// then、promise およびエラー関連の遅延メソッドを追加します。
jQuery.extend(deferred, {
then: function (doneCallbacks, failedCallbacks) {
deferred.done(doneCallbacks).fail(failCallbacks) );
これを返します;
}、
fail:failDeferred.done、
rejectWith:failDeferred.resolveWith、
rejected:failDeferred.isResolved、
// return 遅延オブジェクトの読み取り専用コピー
// obj がパラメータとして渡された場合、promise 関連のメソッドがこの obj
promise に追加されます: function (obj) {
if (obj == null) {
if (promise) {
return promise;
}
promise = obj = {};
var i =promiseMethods.length;
while (i- -) {
obj[promiseMethods[i]] = deferred[promiseMethods[i]]
}
return
}
}; 🎜>// コールバック関数のキューが 1 つだけであることを確認します。これは、タスクが成功または失敗することを意味します。
deferred.done(failDeferred.cancel).fail(deferred.cancel);削除キャンセル関数
deferred.cancel;
// 現在作成されている関数をパラメータとして渡します
if (func) {
func.call(deferred, deferred); >}
return deferred;
});
上記のコードが読みにくいと感じても、問題はありません。
コードをコピー
arr = {
add: function (item) {
items.push(item);
},
length: function () {
return items.length;
},
clear: function () {
items = [];
promise: function () {
if (promise) {
約束を返す;
}
var obj = promise = {};
obj.length = arr.length; .promise;
return obj;
}
};
return arr;
上記のコードは、 add()、length()、clear()、promise() などのメソッドを含む配列オブジェクト。
promise() が現在の Arr オブジェクトのコピーを返す場合、要素を追加することのみが可能ですが、内部配列をクリアすることはできません。
コードをコピーします
コードは次のとおりです。
varpromise();
promise.add(4); 🎜>/ / 4
console.log(promise.length());
// エラー: TypeError: Promise.clear は関数ではありません
promise.clear();
deferred.promise() と deferred.promise().promise()
同じ機能を実現する前述の 2 つのコードを覚えていますか?
コードをコピー
コードは次のとおりです。
function getData() {
return $.get ('/foo/');
}
function showDiv() {
// ここでpromise()を返すか、遅延オブジェクトを直接返すと、コードは正しく実行されます。
return $.Deferred(function (dfd) {
$('#foo').fadeIn(1000, dfd.resolve);
}).promise();
$.when(getData(), showDiv()).then(function (ajaxResult) {
console.log('アニメーションと AJAX リクエストの両方が完了しました!');
}); では、なぜこれら 2 つの方法が機能するのか考えたことはありますか? jQuery のソース コードを詳しく調べると、obj1.promise() を取得するために $.when(obj1, obj2, ...) が内部実装されていることがわかります:
コードをコピー
コードは次のとおりです:
if ( object && jQuery.isFunction( object.promise ) ) {
object.promise().then( iCallback(lastIndex), deferred.reject );
それでは、上記の showDiv の戻り結果を見てみましょう:
それが遅延オブジェクトの場合、$.when() は次の方法で Promise を取得します:
$.Deferred().promise()
deferred.promise() オブジェクトの場合、$.when() は次の方法で Promise を取得します:
$.Deferred().promise().promise()
それは次の意味ですか: $.Deferred().promise() === $.Deferred().promise().promise()
例を通してアイデアを検証してみましょう:
var deferred = $.Deferred(),
promise = deferred.promise( );
/ / true
promise === replace.promise();
// true
promise ().promise().promise(); >
もちろん、この結果は推測されたものであり、Deferred のソース コードを直接見ると、次の結果が簡単にわかります。
promise: function (obj) {
if (obj == null) {
// ここで、 Promise がすでに存在する (.promise() と呼ばれる) 場合、それは再作成されません。
if (promise) {
return Promise;
}
promise = obj = {};
var i =promiseMethods.length;
while (i--) {
obj[promiseMethods[i]] = deferred[promiseMethods[i]];
return obj;
}
概要
1. deferred.promise() は、遅延オブジェクトの読み取り専用プロパティを返します。
2. タスクは遅延オブジェクトを返さず、deferred.promise() オブジェクトを返すことをお勧めします。このようにして、外部関係者がタスクの内部プロセスを任意に変更することはできません。
3. deferred.promise() === deferred.promise().promise() (コード推論とソースコード分析の 2 つの観点からこの結論に達しました)
この記事は Sanshengshi によって書かれていますオリジナルはブログにあり、ブログパークに初公開されたものです。転載する場合は出典を明記してください。