3

jQuery などの JavaScript ツールキットはすべてコールバック関数に関するものであり、これらのコールバックは匿名で定義されることがよくあります。例: 一部の Web ページでは、表にメッセージのリストが表示されます。このテーブルを更新するには、まずサーバーに現在のすべてのメッセージのリストを (ID として) 要求し、次に、まだ不明なメッセージ ID のコンテンツを取得します。

function fnUpdateMessages() {
   $.ajax({
      type: 'POST',
      data: { action: 'get_message_ids' },
      success: function(sData) {
         var aMessageIds = sData.split(/,/);
         var aUnknownIds = fnWhichIdsAreNotInTable(aMessageIds);
         $.ajax({
            type: 'POST',
            data: {
               action: 'get_message_contents',
               ids: aUnknownIds.join(',')
            },
            success: function(oData) {
               for (var id in oData.messages) {
                  fnInsertMessage(oData.messages[id]);
               }
            }
         );
      }
   );
}

私がどこに行くか分かりますか?たった 2 回の AJAX 呼び出しの後、インデントがレベル 6 になるため、このコードは醜いです。もちろん、無名関数をファイル スコープで個別の関数に分割することもできますが、通常は名前空間を汚染し (これを別の無名関数呼び出しでラップしてさらに混乱させない限り)、これらの関数間の強い結合を壊します。単独では使用できません。これらは、元の関数の 2 番目と 3 番目の部分に似ていますfnUpdateMessages

私がもっと欲しいのは、次のようなものです:

function fnUpdateMessages() {
   $.ajax({
      type: 'POST',
      data: { action: 'get_message_ids' },
      success: continue(sData)
   });

   var aMessageIds = sData.split(/,/);
   var aUnknownIds = fnWhichIdsAreNotInTable(aMessageIds);
   $.ajax({
      type: 'POST',
      data: {
         action: 'get_message_contents',
         ids: aUnknownIds.join(',')
      },
      success: continue(oData)
   );

   for (var id in oData.messages) {
      fnInsertMessage(oData.messages[id]);
   }
}

continue(var1, var2, [...])このスニペットは、外側の関数スコープに続くすべてのものを本体とする匿名のコールバック関数を定義する、新しい架空の構文を導入しています。これにより、これらのコールバック関数が同期コードのように見えます。これは標準の JS ではないため、明らかに前処理する必要があります。

このようなプリプロセッサの作成を検討する前に、このようなものが既に存在するかどうかを知りたいですか?

PS このアイデアが気に入ったら盗んでください。現時点では、さらに別のプロジェクトを実行する余裕はありません。コメント内のリポジトリへのリンクは、実際のコードに到達した場合に最適です。

4

3 に答える 3

2

解決策は 2 つだけです。

最初のものは本当に悪いです。最初の ajax リクエストを同期させる必要がありますが、スクリプトは結果が利用可能になるまでブロックされます。これは本当に悪い解決策です。ajax リクエストを同期させるべきではありません。

2 つ目は、$.ajax によって返される遅延オブジェクトで jQuery.pipe 関数を使用します (jquery > 1.5 を使用する必要があります)。次のようにパイプを使用してコールバックをチェーンできます(内部関数を使用して読みやすくします):

[編集] : jquery 1.8 以降、 deferred.pipe の代わりに deferred.then を使用する必要があります。

    function fnUpdateMessages() {
        var getMessages = function() {
            return $.ajax({
                type: 'POST',
                data: { action: 'get_message_ids' },
            });
        };

        var getContents = function(aUnknownIds) {
            return $.ajax({
                type: 'POST',
                data: {
                    action: 'get_message_contents',
                    ids: aUnknownIds.join(',')
                },
            });
        };

        var insertMessages = function(oData) {
            for (var id in oData.messages) {
                fnInsertMessage(oData.messages[id]);
            }
        };

        getMessages()
            .then(getContents)
            .done(insertMessages);
     }
于 2013-02-11T09:30:07.720 に答える
1

はいあります。これはjwacs - JavaScript With Advanced Continuation Supportと呼ばれます。簡単に言えば、継続を利用してプログラムの実行を中断します。その後、継続を呼び出してプログラムの実行を再開できます。継続では、作成時のプログラムの状態が常に保持されます。

これはJavaScript のトランポリンに少し似ていますが、トランポリンは Mozilla 製品 (Firefox と Rhino) でのみサポートされているジェネレーターに依存しています。トランポリンに興味があるなら、非同期書き込みを耐えられるようにするためのライブラリーを作成しました。これはファイバーと呼ばれ、協調的な Java スレッドに少し似ています。

一方、jwacs は通常の JavaScript にコンパイルされます。したがって、どのプラットフォームでも使用できます。Firefox や Rhino だけではありません。継続とは何かを理解したい場合は、次の StackOverflow の質問と回答を読むことをお勧めします。

質問:継続とコールバックの違いは何ですか?

答え: https://stackoverflow.com/a/14022348/783743

于 2013-02-11T09:36:39.887 に答える
1

オプションにコールバックを含める代わりに、jQuery の deferred を使用してコールバックを連鎖させることができます。

function fnUpdateMessages() {
   $.ajax({
      type: 'POST',
      data: { action: 'get_message_ids' }
   ).done(function(sData) {
      var aMessageIds = sData.split(/,/);
      var aUnknownIds = fnWhichIdsAreNotInTable(aMessageIds);
      $.ajax({
         type: 'POST',
         data: {
            action: 'get_message_contents',
            ids: aUnknownIds.join(',')
         }
      }).done(function(oData) {
         for (var id in oData.messages) {
            fnInsertMessage(oData.messages[id]);
         }
      });
   });
}

完璧ではありませんが、リクエストごとに数レベルのインデントを節約できます。

詳細については、 $.ajaxのドキュメントを参照してください。

于 2013-02-11T09:20:48.697 に答える