2013-04-05 10 views
6

この質問は慎重に蒸留されたnot asynchronous function executed as jQuery Deferredのバージョンです。 ()関数を呼び出し通知にもかかわらず、ここでprogressイベントが発生しません -jqueryの遅延に関するタイミング問題

  1. http://jsfiddle.net/XSDVX/1/

    は、我々は2 jsfiddlesを持っています。

  2. http://jsfiddle.net/UXSbw/1/ - ここで、progressイベントは期待どおりに発生します。

唯一の違いは、1行のコードである:

setTimeout(dfd.resolve,1); 

dfd.resolve(); 

に対する質問は、次のとおり

  1. 解決を遅らせると、このコールバックが返される前に呼び出される.notifyを.threadキャッチするのはどうですか?それについて考える。その後、最初のパラメータから返された遅延オブジェクトを取得し、そこから新しい遅延オブジェクトを作成し、進行状況および失敗イベントにバインドします。通知が遅延が返される前に呼び出された場合、setTimeoutを使用してもそれをキャッチするのはどうですか? (これを尋ねるためhttps://stackoverflow.com/users/400654/kevin-bのおかげで)

  2. は私がsetTimeout()を取り除くことができますし、まだ進行中のコールバックが発射していますか?

+3

ただ、最後の質問からいくつかの背景情報を追加するには、setTimeoutメソッドが必要とされる理由は、繰延オブジェクトがバインドされた多くのprogressイベントを持つことができません解決されます。解決を遅らせることによって、 '.then'は進捗イベントにバインドすることができます。 –

+0

すべての微妙な結果が分かると、これは非常に厄介な動作です。 – mnowotka

+0

私はそれほど理解していない部分があります。私たちが解決を遅らせると、このコールバックが戻る前に呼び出される.notifyをキャッチすることはどうですか?それについて考える。その後、最初のパラメータから返された遅延オブジェクトを取得し、そこから新しい遅延オブジェクトを作成し、進行状況および失敗イベントにバインドします。通知が遅延が返される前に呼び出された場合、setTimeoutを使用してもそれをキャッチするのはどうですか? –

答えて

1

大きなリファクタを作成しました。ここには進捗監視のあるone final working example,があります。

ここで重要な部分です。決意は(with one exception)と呼ばれた後

  • のjQueryのDeferredの作り方は、任意の進行状況のコールバックを実行しません。あなたの例(setTimeoutなし)では、遅延は直ちに解決され、進捗を実行する機会はありません。
  • の前のすべてのコールバックのフックを実行して、の前に最後のDeferredを開始します。これは、の後に最終的なDeferred(現在のビーコン)を実行ファンクションに渡すことによって実現されます。
  • APIをリファクタリングして、実行される関数が遅延に依存しないようにしました。
  • このソリューションは、実行チェーンを継続するために、memo.then関数内で局所的(反復機能を減らすために)のDeferredというclosureを使用します。

編集:最初の質問を忘れました。 この動作は、closure( "x"関数のdfd変数)の手段によって実現されます。

実行チェーンのすべてのDeferredsが作成され、 "executePromiseQueueSync"のdone、fail、progressのフックが実行されたため、関数 "x"がすぐに戻ります(通知イベントをトリガーして処理できるようになりました)。フック)。

また、setTimeoutの関数はクロージャのdfdを「閉じる」ので、「x」が返っても変数にアクセスできます。 "then"コールは、最初のものにリンクされている次の遅延を作成することによって継続されます。

JS VMが実行すると(それ以外の処理はない)、setTimeoutは関連する関数をトリガし、クロージャの手段によって「閉じた」dfd変数にアクセスします。 Deferredが解決され、チェーンは続行できます。

EDIT2:Here is a refactored version彼らは彼らの進歩のために自分の発信者に通知し、長い実行し、繰延サポートしている機能のサポートが追加されます。

EDIT3:ここではanother versionです。アンダースコアバインディングはなく、jq-uiプログレスバーの例もあります。

ところで、これは複雑なアプリの初期化ルーチンにとって非常に良いアイデアです。

(最初のバージョンの)ソース

function executePromiseQueueSync(queue, beacon){ 
    var seed = $.Deferred(), 
     le = queue.length, 
     last; 
    beacon.notify(0); 
    last = _.reduce(queue, function(memo, ent, ind){ 
     var df = $.Deferred(); 
     df.then(function(){ 
      console.log("DBG proggie"); 
      beacon.notify((ind+1)/le*100); 
     }); 
     console.log("DBG hook funk "+ind); 
     memo.then(function(){ 
      console.log("DBG exec func "+ind); 
      ent.funct.apply(null, ent.argmnt); 
      df.resolve(); 
     }); 

     return df.promise(); 
    }, seed.promise()); 
    last.then(function(){ 
     beacon.resolve(100) 
    }); 
    seed.resolve(); // trigger 

    return beacon.promise(); 
} 

function x(){ 
    // do stuff 
    console.log("blah"); 
} 

var promisesQueue = [], 
    beacon = $.Deferred(); 

promisesQueue.push({funct: x, argmnt:[]}); 
promisesQueue.push({funct: x, argmnt:[]}); 
promisesQueue.push({funct: x, argmnt:[]}); 

function monTheProg(pct) 
{ 
    console.log('progress '+pct); 
} 

// first hook, then exec 
beacon.then(function(){ 
     console.log('success'); 
    }, function(){ 
     console.log('failure'); 
    }, monTheProg); 

// do the dance 
executePromiseQueueSync(promisesQueue, beacon)