23

わかりました、Javascript が C# や PHP ではないことを理解していますが、私は Javascript の問題 (JS 自体ではなく、私の使用法) に戻ってきます。

私は機能を持っています:

function updateStatuses(){

showLoader() //show the 'loader.gif' in the UI

updateStatus('cron1'); //performs an ajax request to get the status of something
updateStatus('cron2');
updateStatus('cron3');
updateStatus('cronEmail');
updateStatus('cronHourly');
updateStatus('cronDaily');

hideLoader(); //hide the 'loader.gif' in the UI

}

問題は、Javascript がコードを先に進めたいという熱烈な欲求のために、「hideLoader」関数が直後に実行されるため、ローダーが表示されないということです。

どうすればこれを修正できますか? 言い換えれば、ページに書いた順序でJavaScript関数を実行するにはどうすればよいですか...

4

9 に答える 9

16

この問題は、AJAXが本質的に非同期であるために発生します。これは、updateStatus()呼び出しが実際に順番に実行されるが、すぐに戻り、JSインタープリターがhideLoader()AJAX要求からデータを取得する前に到達することを意味します。

hideLoader()AJAX呼び出しが終了したイベントでを実行する必要があります。

于 2010-04-14T13:22:27.307 に答える
14

AJAX プログラミングを行っている場合は、JavaScript を手続き型ではなくイベント ベースと考える必要があります。2 番目の呼び出しを実行する前に、最初の呼び出しが完了するまで待つ必要があります。これを行う方法は、最初の呼び出しが終了したときに起動するコールバックに 2 番目の呼び出しをバインドすることです。AJAX ライブラリの内部動作について詳しく知らなければ (ライブラリを使用していることを願っています)、これを行う方法を説明することはできませんが、おそらく次のようになります。

showLoader();

  updateStatus('cron1', function() {
    updateStatus('cron2', function() {
      updateStatus('cron3', function() {
        updateStatus('cronEmail', function() {
          updateStatus('cronHourly', function() {
            updateStatus('cronDaily', funciton() { hideLoader(); })
          })
        })
      })
    })
  })
});

アイデアは、updateStatus通常の引数と、終了時に実行するコールバック関数を受け取ることです。onCompleteそのようなフックを提供する関数に実行する関数を渡すのは、かなり一般的なパターンです。

アップデート

jQuery を使用している場合は、 http $.ajax(): //api.jquery.com/jQuery.ajax/を参照してください。

コードはおそらく次のようになります。

function updateStatus(arg) {
  // processing

  $.ajax({
     data : /* something */,
     url  : /* something */
  });

  // processing
}

次のように関数を変更して、2 番目のパラメーターとしてコールバックを受け取ることができます。

function updateStatus(arg, onComplete) {
  $.ajax({
    data : /* something */,
    url  : /* something */,
    complete : onComplete // called when AJAX transaction finishes
  });

}

于 2010-04-14T13:33:54.427 に答える
10

あなたがする必要があるのは、コードにこれを含めることだけだと思います:

async: false,

したがって、Ajax 呼び出しは次のようになります。

jQuery.ajax({
            type: "GET",
            url: "something.html for example",
            dataType: "html",
            async: false,
            context: document.body,
            success: function(response){

                //do stuff here

            },
            error: function() {
                alert("Sorry, The requested property could not be found.");
            }  
        });

などのためXMLに変更する必要があることは明らかですが、ここでの主なポイントは、成功呼び出しが返される (または場合によっては失敗する) まで待機し、続行するように JS エンジンに指示することです。これには欠点があることに注意してください。それは、ajax が戻るまでページ全体が応答しなくなることです!!! 通常はミリ秒以内です。これは大したことではありませんが、さらに時間がかかる可能性があります。JSONasync: false,

これが正しい答えであり、あなたの助けになることを願っています:)

于 2011-07-14T12:35:42.193 に答える
5

プロジェクトの 1 つに似たようなものがあり、カウンターを使用して解決しました。呼び出しごとにカウンターを増やし、updateStatusAJAX 要求の応答関数で減らす場合 (使用している AJAX JavaScript ライブラリによって異なります)。

カウンタがゼロになると、すべての AJAX リクエストが完了し、 を呼び出すことができますhideLoader()

サンプルは次のとおりです。

var loadCounter = 0;

function updateStatuses(){
    updateStatus('cron1'); //performs an ajax request to get the status of something
    updateStatus('cron2');
    updateStatus('cron3');    
    updateStatus('cronEmail');
    updateStatus('cronHourly');
    updateStatus('cronDaily');
}

function updateStatus(what) {
    loadCounter++;

    //perform your AJAX call and set the response method to updateStatusCompleted()
}

function updateStatusCompleted() {
    loadCounter--;
    if (loadCounter <= 0)
        hideLoader(); //hide the 'loader.gif' in the UI
}
于 2010-04-14T13:34:59.173 に答える
2

これは、コードの実行順序とは関係ありません。

ローダーイメージが表示されない理由は、関数の実行中にUIが更新されないためです。UIで変更を行った場合、関数を終了してブラウザに制御を戻すまで、変更は表示されません。

画像を設定した後にタイムアウトを使用して、残りのコードを開始する前にブラウザにUIを更新する機会を与えることができます。

function updateStatuses(){

  showLoader() //show the 'loader.gif' in the UI

  // start a timeout that will start the rest of the code after the UI updates
  window.setTimeout(function(){
    updateStatus('cron1'); //performs an ajax request to get the status of something
    updateStatus('cron2');
    updateStatus('cron3');
    updateStatus('cronEmail');
    updateStatus('cronHourly');
    updateStatus('cronDaily');

    hideLoader(); //hide the 'loader.gif' in the UI
  },0);
}

コードが順不同で実行されているように見える可能性がある別の要因があります。AJAXリクエストが非同期の場合、関数はレスポンスを待ちません。ブラウザが応答を受信すると、応答を処理する関数が実行されます。応答の受信後にローダーイメージを非表示にする場合は、最後の応答ハンドラー関数の実行時に非表示にする必要があります。応答は、要求を送信した順序で到着する必要はないため、最後の応答が来たときに知った応答の数を数える必要があります。

于 2010-04-14T13:27:48.660 に答える
1

Firebug をインストールしてから、次のような行を showLoader、updateStatus、hideLoader のそれぞれに追加します。

Console.log("event logged");

関数への呼び出しがコンソール ウィンドウに一覧表示され、順番に表示されます。問題は、「updateStatus」メソッドが何をするかです。

おそらく、バックグラウンド タスクを開始してから戻るため、バックグラウンド タスクが終了する前に hideLoader の呼び出しに到達します。あなたの Ajax ライブラリにはおそらく "OnComplete" または "OnFinished" コールバックがあります - そこから次の updateStatus を呼び出します。

于 2010-04-14T13:33:13.907 に答える
1

他の人が指摘したように、同期操作を実行したくありません。非同期を採用します。これは、AJAX の A が表すものです。

同期と非同期の優れた類推について言及したいと思います。投稿全体は GWT フォーラムで読むことができます。ここでは、関連する類推のみを含めています。

あなたがするかどうか想像してみてください...

あなたはソファに座ってテレビを見ていましたが、ビールがなくなったことを知って、配偶者に酒屋に駆け寄ってビールを持ってきてほしいと頼みました。配偶者が玄関から出て行くのを見るとすぐに、あなたはソファから立ち上がり、キッチンに足を踏み入れて冷蔵庫を開けます。驚いたことに、ビールはありません。

もちろんビールはありません。あなたの配偶者はまだ酒屋への旅行中です。ビールを飲む前に、彼が戻ってくるまで待たなければなりません。

しかし、あなたはそれを同期させたいと言いますか?もう一度想像してください...

...配偶者がドアから出て行く...今、あなたの周りの全世界が止まり、息をすることも、ドアに応答することも、ビールを取りに町を走っている間、ショーを見終えることもできません。筋肉を動かさずにそこに座って、意識を失うまで青くなります...しばらくして、EMTと配偶者に囲まれて目を覚まし、ああ、ねえ、ビールを手に入れました.

これはまさに、同期サーバー呼び出しを行うことを主張するときに起こることです。

于 2010-04-14T14:17:47.100 に答える
0

updateStatus 呼び出しを別の関数に移動します。新しい関数をターゲットとして setTimeout を呼び出します。

ajax リクエストが非同期の場合、どのリクエストが完了したかを追跡する必要があります。各コールバック メソッドは、それ自体のどこかに「完了」フラグを設定し、それが最後に行われたかどうかを確認できます。そうであれば、hideLoader を呼び出すようにします。

于 2010-04-14T13:36:18.317 に答える