現在のエンタープライズプロジェクトの開発中に、jQuery要素のコレクションの遅延処理を実装する必要がありました。コンテンツを順番にロードする必要があるウィジェットのセットがあり、ロードは非同期に発生しました。
$.fn
-
eachDeferred
小さな拡張子を書く必要がありました。
アイデアは非常に単純です-ループで処理する必要があるjQuery要素のコレクションがありますが、反復は現在の要素の処理が完了した後にのみ行われるべきです。
議論の主題には、 $.Deferred
jQueryオブジェクトの$.Deferred
に関する知識が含まれることに注意してください。 (function ($) { $.fn.extend({ eachDeferred: function (c) { var that = this, dfd = $.Deferred(), elms = $.makeArray(that), i = elms.length, next = function () { setTimeout(function () { elms.length ? cb(elms.shift()) : dfd.resolve(that); }, 0); }, cb = function (elm) { $.when(c.call(elm, i - elms.length, $(elm))).done(function (result) { dfd.notify(result); next(); }); }; next(); return dfd.promise(); } }); })(jQuery);
反復関数は、現在の反復の完了を判断するために、
$.Deferred
オブジェクトを返す必要があります。
eachDeferred
プラグインコード
eachDeferred
も、コールチェーンで使用できる
$.Deferred
オブジェクトを返します。 オブジェクトは、
notify/progress
を介して各反復の結果を
notify/progress
、反復結果(ループハンドラー関数の
$.Deferred.resolve(arg)
から返すことができる
$.Deferred.resolve(arg)
をハンドラー
.progress(function(arg){})
(可能な場合)。
コードからの小さなコピー/貼り付け
that.widgets.eachDeferred(function (i, widget) { return that.renderContent(widget); }).done(dfd.resolve);
renderContent
は、サーバーからデータを非同期にプルし、ウィジェットのコンテンツを表示します。 視覚的には、各ウィジェットが優先度順にロードされているように感じられます。 通常のメカニズム
$.Deferred
(
$.get().success()
)ウィジェットを使用する場合、ウィジェットはランダムに表示されます-むしろロードされます。
別の例
var dfd = $.Deferred(), _r = []; xml.children("Tree").eachDeferred(function (i, xmlNode) { return that._buildTreeContents(xmlNode); }).progress(function (treeContents) { _r.push(treeContents); }).done(function () { dfd.resolve(_r); }); return dfd.promise();
_buildTreeContents
は、ツリーのマークアップを非同期で構築し、各反復の結果を渡します(配列に保存します)。 コレクションの処理の最後に、ページに挿入できる一般的なツリーレイアウトがあります。
このようなメカニズムにより、同期(静的)コレクションの非同期処理が可能になります。
小さな作業例。PS
next()
関数内では奇妙なタイムアウトに見えるかもしれません。 jQueryコードが原因でタイムアウトが必要です
.notify()
は同じタイムアウトで呼び出されます。 これは、ブラウザーが現在のJavascript VMスタックの処理を完了することができるようにするために行われます。
私のコードでタイムアウトを行わない場合、次の反復呼び出しは通常のスタックに移動し、
.notify()
よりも
早く呼び出され
ます -最初に反復の終了を通知してから、次に移動する必要があります。