长轮询冻结浏览器并阻止其他ajax请求

我试图在我的Spring-MVC Web App中实现长轮询,但是在4-5继续AJAX请求之后它冻结了我的浏览器和其他请求。我不知道什么是在这里是我的相关代码。

控制器方法:(服务器端): –

@Asynchronous @RequestMapping("/notify") public @ResponseBody Events notifyEvent(HttpServletRequest request) { Events events = null; try { events = (Events) request.getSession(false).getServletContext().getAttribute("events"); System.out.println("Request Came from" + ((com.hcdc.coedp.safe.domain.User) request.getSession(false).getAttribute(Constants.KEY_LOGGED_IN_USER)).getLoginId()); if (!events.getTypeOfEvents().isEmpty()) { System.out.println("Removing older entries"); events.getTypeOfEvents().clear(); } while (!events.isHappend()) { //Waiting for event to happen. } events = Events.getInstance(); events.setHappend(false); request.getSession(false).getServletContext().setAttribute("events", events); }catch (Exception e) { e.printStackTrace(); } return events; } 

长轮询脚本(客户端): –

 $(document).ready(function() { $.ajaxSetup({ async:true//set a global ajax requests as asynchronus }); alert('Handler for .onload() called.'); waitForMsg(); }); function waitForMsg(){ xhr= $.ajax({ type: "POST", url: '/notification/notify', async: true, /* If set to non-async, browser shows page as "Loading.."*/ cache: false, timeout:50000, /* Timeout in ms */ global:false, success: function(data){ /* called when request to notifier completes */ /* Doing smthing with response **/ setTimeout( waitForMsg, /* Request next message */ 1000 /* ..after 1 seconds */ ); }, error: function(XMLHttpRequest, textStatus, errorThrown){ addmsg("error", textStatus + " (" + errorThrown + ")"); setTimeout( waitForMsg, /* Try again after.. */ 15000); /* milliseconds (15seconds) */ } }); }; 

更新:

 function updateFeed(event, data) { var f=eval(data); alert(f.typeOfEvents.length); } function catchAll(event, data, type) { console.log(data); alert("error"); console.log(type); } $.comet.connect('/notification/notify'); $(document).bind('feed.comet', updateFeed); $(document).bind('.comet', catchAll); 

两个警报框都没有弹出…… 🙁

看来你的浏览器代码中有一个空的while循环..这是一种非常CPU的等待事件的方式。

如果没有发生任何事件,客户端将在您所需的超时50秒后终止请求。 但是我不确定服务器线程是否也被杀死,或者它是否“永远”(除非有事件)。 下一个请求将启动第二个服务器线程,该线程在while循环中也会挂起。 也许空的while循环量对于服务器来说是一种过度杀伤,因此它会停止接受任何更多的请求。 因此,在一些请求(每个都触发了无休止的服务器线程)之后,客户端会在新请求上永远等待…因为它无法由服务器处理。

ps:成功时你评论等待1秒,但将超时设置为10000(10秒)

好像您遇到了会话文件锁定

对于PHP

不需要会话值时使用session_write_close()

我遇到了类似的问题,我的浏览器在某种程度上被AJAX请求所困扰。 提示:改为直接使用waitForMsg() ,尝试setTimeout(“waitForMsg()”,10)

仅供参考,这是一个可能对您有帮助的项目: https : //github.com/SeanOC/jquery.comet

一般情况下,我会搜索可以支持Web套接字的JavaScript彗星API,如果在客户端/服务器上可用,则可以优雅地回退到长轮询。 API应该处理所有血腥细节,让您专注于应用程序。

这是关于该主题的旧dojo文章的链接: http : //dojotoolkit.org/features/1.6/dojo-websocket

祝你好运。

您可以尝试使用jQuery deferred重写行为:

 function setShortTimeout() { setTimeout(waitForMsg, 1000); } function setLongTimeout() { setTimeout(waitForMsg, 15000); } $(document).ready(function() { $.ajaxSetup({ async:true//set a global ajax requests as asynchronus }); alert('Handler for .onload() called.'); $.when(waitForMsg()) .done(successHandler, setShortTimeout) .fail(errorHandler, setLongTimeout); }); function waitForMsg(){ return $.ajax({ type: "POST", url: '<%=request.getContextPath()%>/notification/notify', async: true, /* If set to non-async, browser shows page as "Loading.."*/ cache: false, timeout:50000, /* Timeout in ms */ global:false }); }; 

errorHandlersuccessHandler将是你的成功:和错误:回调,我为了清楚而省略了它们的setTimeout部分被删除(因为它现在是deferred.done()和.fail()回调的一部分)。

如果有效,请告诉我。

我是一名PHP开发人员,但我遇到了你的问题,可能是同样的行为。 所以我给你2美分,希望它能帮到你。

确实让我怀疑问题的那条线是:

 events = (Events) request.getSession(false).getServletContext().getAttribute("events"); 

在PHP中,会话存储在文件中,如果我们在会话打开时对php脚本进行长轮询,则会遇到竞争条件问题。

原理很简单:

  1. 当请求打开会话时,文件将被锁定,直到会话关闭。
  2. 如果其他请求到达服务器,它们将被锁定,直到会话从上一个请求释放。

在长轮询的情况下,如果会话在获取信息之后打开并且没有关闭(至少在等待事件之前),所有请求都被锁定,如果你是的话,你不能去网站的任何其他地方在其他页面上使用会话。 即使您打开一个新选项卡,因为对于一个浏览器只有一个会话,您将被锁定。

可能是这样的:

  xhr= $.ajax({ (...) 

在你的waitForMsg函数中。

尝试

  var xhr = (...) 

可能是您在全局对象中声明了xhr,因此无法响应两个不同的请求。