1

複数の AJAX 要求を迅速または同時に送信する必要がある AJAX 集中型アプリケーションがあります。次のコードは、アプリ全体で使用する AJAX POST 呼び出しを送信するための単純なラッパーです。2 つの注意事項があります。

1)リクエストを行う前にユーザーのインターネット接続をテストできるようにしたいので、接続がダウンしている場合に通知できます。

2) 接続がダウンしていて、アプリを引き続き使用すると、より多くの AJAX 呼び出しが生成される場合、それらの呼び出しをキューに入れ、接続が回復したら 1 つずつ送信したいと考えています。

接続チェックとキューイングは機能しますが、ユーザーがオンラインに戻ったときに、要求の一部のみがサーバーに送信され、元の順序で送信されたように見えます。私は何が欠けていますか?すべてのリクエストが送信されていないのはなぜですか? また、順番どおりに送信されていないのはなぜですか?

そして、誰かが気付く前に、jQuery を使用したこのトピックに関する他の解決策をいくつか見てきました。私はそれらを使用することに反対しているわけではありません。このコードが機能しない理由を理解したいだけです。前もって感謝します。

window.connectionState = true
window.xhrQueue = []
window.pingInterval

function xhrPost(url, packet, before, after) {
  if (!url || typeof(url) !== "string") {
    console.log("invalid url supplied in xhr call.")
    return false
  }

  var mainRequest = function() {
    var xhr= new XMLHttpRequest()

    if (typeof(after) === "function") {
      xhr.onreadystatechange = function(){
        if (xhr.readyState == 4) {
          after(xhr)
          return true
        }
      }
    }

    if (typeof(before) === "function") {
      before()
    }

    xhr.open("POST",url,true)
      if (packet) {
        xhr.send(JSON.stringify(packet))
      }
      else {
        xhr.send()
      }
  }

  ping(mainRequest)
}

function ping(mainRequest) {

  // Create pingXhr to test connection
  var pingXhr = new XMLHttpRequest()

  pingXhr.onreadystatechange = function(){
    // If pingXhr comes back successfully...
    if (pingXhr.readyState == 4) {
      if (pingXhr.status == 200) { 
        // If pingXhr comes back from being down, update user
        if (window.connectionState !== true) {
          setTimeout(function() { alert("And we're back! Your connection seems to be working now. Keep editing.") }, 1)
        }
        // If there are requests waiting, send them in order, then remove them
        if (window.xhrQueue.length > 0) {
          for (var i in window.xhrQueue) {
            ping(window.xhrQueue[i])
            window.xhrQueue.splice(i, 1)
            clearInterval(window.pingInterval)
          }
        }
        // Otherwise, just make the singular request
        else {
          mainRequest()
        }
        // Reset xhrQueue since stuff is successful, change connection to true, and unset onbeforeunload message
        window.xhrQueue = []
        window.connectionState = true
      }
      // If there was a problem with the request
      else {
        // Notify the user their internet is down
        if (window.connectionState === true) {
          setTimeout(function() { alert("It seems you have momentarily lost internet connectivity.") }, 1)
        }
        // If there are no requests in the xhrQueue, create the timeout. Otherwise, just add to the queue
        if (window.xhrQueue.length === 0) {
          window.pingInterval = setInterval(function(){ ping() }, 3000)
        }
        // Add the request to the xhrQueue to be processed in order
        if (typeof(mainRequest) === "function") {
          window.xhrQueue.push(mainRequest)
        }
        window.connectionState = false
      }
    }
  }
  pingXhr.open("GET","/some/url/here",true)
  pingXhr.send()
}
4

2 に答える 2

1

一度にすべてを起動しているため、他のハンドラーよりも戻るのに時間がかかるものがあるため、それらのハンドラーが最初に実行されます。

次のものを送信するには、コールバックを使用して一度に 1 つずつ送信することをお勧めします

于 2012-06-26T23:46:42.740 に答える
1

push() を使用してエントリをキューに配置し、ループで splice() を使用してそれらを削除しているようです。それは適切に機能しない可能性があります-スプライスは配列内のインデックスを反復処理するときに変更するため、それらの一部/ほとんどをスキップします。

常に最初の要素をオフにするようにループを変更すると、よりうまく機能します。

追加するために編集:おそらく、ここでも for-in ループを実行したくないでしょう。オブジェクトの反復処理中にオブジェクトのキーを変更することは、一般的には良い考えではありません。

何かのようなもの:

while (window.xhrQueue.length > 0) {
    ping(window.xhrQueue[0]);
    window.xhrQueue.splice(0, 1);
}

または、キューに入れられたすべてのリクエストを同時に実行しようとする代わりに、onreadystatechange ハンドラをキューから次のエントリを取得して、そのリクエストを送信するだけにすることもできます。

于 2012-06-26T23:48:18.407 に答える