eachDeferred-遅延コレクション処理、1つずつ

現在のエンタープライズプロジェクトの開発中に、jQuery要素のコレクションの遅延処理を実装する必要がありました。コンテンツを順番にロードする必要があるウィジェットのセットがあり、ロードは非同期に発生しました。 $.fn - eachDeferred小さな拡張子を書く必要がありました。

アイデアは非常に単純です-ループで処理する必要があるjQuery要素のコレクションがありますが、反復は現在の要素の処理が完了した後にのみ行われるべきです。

議論の主題には、 $.Deferred jQueryオブジェクトの$.Deferredに関する知識が含まれることに注意してください。

 (function ($) { $.fn.extend({ /* * Iterates over jQuery object collection using deferred callbacks. * the function assigned for iterator should return promise. * resolved promises notify the main deferred, so we can track each loop result. * returns promise. */ 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() より早く呼び出されます -最初に反復の終了を通知してから、次に移動する必要があります。

Source: https://habr.com/ru/post/J143592/


All Articles