javascript - 离线时排队多个 AJAX 请求,连接返回时发送

标签 javascript ajax asynchronous xmlhttprequest

我有一个 AJAX 密集型应用程序,需要快速或同时发送多个 AJAX 请求。以下代码只是一个简单的包装器,用于发送我在整个应用程序中使用的 AJAX POST 调用。有 2 个注意事项:

1) 我希望能够在发出请求之前测试用户的互联网连接,以便在他们的连接断开时通知他们。

2) 如果他们的连接断开并且他们继续使用该应用程序,这会生成更多的 AJAX 调用,我想将这些调用排队,并在连接恢复后将它们一一发送。

连接检查和排队工作,但是当用户重新上线时,只有他们的一些请求被发送到服务器,而且他们似乎被乱序发送了。我错过了什么?为什么没有发送所有请求,为什么它们不按顺序发送?

在任何人注意到之前,我已经看到了一些涉及 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()
}

最佳答案

看起来您正在使用 push() 将条目放入队列,然后在循环中使用 splice() 来删除它们。这不太可能正常工作 - 它会跳过其中的一些/大部分,因为拼接会在您迭代数组中的索引时修改它们。

如果您将循环更改为始终取下第一个元素,效果会更好。

编辑添加:您可能也不想在这里做一个 for-in 循环。在迭代对象时修改对象的键通常不是一个好主意。

类似于:

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

或者不是尝试同时运行所有排队的请求,您可以让 onreadystatechange 处理程序从队列中获取下一个条目并发送该请求。

关于javascript - 离线时排队多个 AJAX 请求,连接返回时发送,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11217402/

相关文章:

javascript - 如何将javascript文件导入qml worker脚本

javascript - 如何在 sencha 的网格中添加页脚

c# - ASP.Net MVC 添加动态 EditorFor 元素

javascript - 所有 JQuery 函数在部分回发时丢失

javascript - JQuery Click 处理程序仅适用于第一个项目

javascript - 使用浏览器滚动条滚动固定的 div 内容

javascript - 具有作用域问题的匿名函数调用

c# - Nunit 使用 .NET 3.5 测试异步代码

android - 如何异步运行 FilterQueryProvider 的查询?

asp.net - 调用 HttpClient.GetAsync : The underlying connection was closed 时出错