非同期関数のシリアル呼び出し

ご存じのように、JavaScript言語はイベント指向プログラミングのパラダイムを追求しています。 これはもちろん良いことですが、ある非同期関数をある非同期関数の後に呼び出し、次に別の非同期関数を呼び出す必要がある場合はどうでしょうか。 これは、複雑なアニメーション、タイムアウト、ajax、あるアニメーションの後に別のアニメーションが続く必要がある場合などに適用されます。



したがって、松葉杖を開発しました。これにより、実行後にコールバックを開始する非同期関数をより明確に呼び出すことができます。 解決策は長い間存在している可能性がありますが、残念ながら、そのような解決策は見つかりませんでした。



UPD

画像

以下は私のソリューションです。これは、 非同期モジュールのこの機能の類似物であり、コメントに示されている他の同様のソリューションの束です。 特にコメントして下さったすべての方、そして独裁者のおかげです。

/ UPD



サイトの架空のパーサーの例(先頭から取得され、エラーが発生する可能性があります)の例を考えてみましょう。解析後、データベースにデータを入力し、入力後にコードを呼び出します。



var html = ''; request.on('response', function (response) { response.on('data', function (chunk) { html = html + chunk; }); response.on('end', function() { //-  parse(html, function(data){ //- ,     addToDatabase(data, function() { doSomething(); }) }); }); });
      
      







多くのネストされたコールバック-ぶんぶんうという音はありません。



 var html = ''; var responceOnEnd = function() { parse(html, parsed); } var parsed = function(data){ addToDatabase(data, addedToDatabase) } var addedToDatabase = function() { doSomething(); } request.on('response', function (response) { response.on('data', function (chunk) { html = html + chunk; }); response.on('end', responceOnEnd); });
      
      







しかし、混同される可能性のあるいくつかの追加変数があります。



これを行うことをお勧めします:



 wait(function(runNext){ request.on('response', runNext); }).wait(function(runNext, response){ response.on('data', function (chunk) { html = html + chunk; }); response.on('end', function() { runNext(html); }); }).wait(function(runNext, html){ parse(html, runNext); }).wait(function(runNext, data){ addToDatabase(data, runNext); }).wait(function(){ doSomething(); })
      
      







面白い? さらに進みましょう。



機能待機。



 //first —  ,   wait = function(first){ //       return new (function(){ var self = this; var callback = function(){ var args; if(self.deferred.length) { /*       */ args = [].slice.call(arguments); /*    -     */ args.unshift(callback); //      self.deferred[0].apply(self, args); //     self.deferred.shift(); } } this.deferred = []; //    this.wait = function(run){ //      this.deferred.push(run); // this      return self; } first(callback); //   }); }
      
      







コードとコメントが透明であるかどうかはわかりません。数秒自分で考えなければなりません:)



明確にするために、いくつかのシーケンシャルアニメーションを作成しました。



  wait(function(runNext){ log('  '); $('#div1').animate({ top: 30 }, 1000, function(){ // -     runNext(1,2); }); }).wait(function(runNext, a, b){ //     log('  , a='+a+' b='+b ); $('#div2').animate({ top: 50 }, 1000, runNext); }).wait(function(runNext){ log('  '); setTimeout(function(){ log('  ') runNext(); }, 2000); }).wait(function(runNext){ log('  '); $('#div3').animate({ left: 50 }, 1000, runNext); }).wait(function(runNext){ log(' '); $('#div1').animate({ top: 0, left: 45 }, 1000, runNext); }).wait(function(){ log(''); });
      
      



JSFidleで例を実行する



どのように機能しますか?

まず、wait関数が呼び出されます。その引数は、次のコードバッチを呼び出すコールバック(この例ではrunNextとして定義されています)として機能する1つの引数ですぐに始まる別の関数です。 現在のステップで受け取った引数の一部を渡すことができるコールバックが実行された後、waitメソッドに渡される次の関数が呼び出されます。この関数の最初の引数はスクリプトの次の部分を呼び出すコールバックで、残りは前のステップでコールバックに渡される引数です。 などなど。



実際には、それだけです。

PS 上で書いたように、私はそのような開発の独自性を確信していません。したがって、Habrasocietyがこの短い記事をプラティティとして評価すると、静かにドラフトに行きます。

記事をお気に入りに追加した人の数から判断すると、この投稿には価値があるので、たぶんそれを隠さないでしょう。



All Articles