jquery实现长轮询
由于http的request-response模式,一般来说只能由客户端发起请求,而服务器端是无法主动将消息推送到客户端的,但是聪明的工程师们还是想出来了很多办法来实现双向通信,如html5带来的websocket或者本文要讲的一种更简单的实现方法,长轮询。
我们都用过微信web版的扫描登录,如果你打开过控制台,就会发现,页面不断的向后台发起请求,如果你不扫描二维码,这个请求会在大概27秒后得到响应,然后重发一个请求,周而复始。如果你扫描了二维码,这个请求就会很快得到响应,这里就用到了长轮询。
一个典型的ajax长轮询请求一般是这样的(本文中的代码均为coffeescript)
callback = (o) ->
doSomethingHere()
(poll = ->
xhr = jQuery.ajax url,
type: method,
dataType: "json",
data: data,
timeout: 30000
success: (o) ->
callback and callback(o)
complete: ->
poll()
)()
通过查阅jquery文档,我们可以知道,complete函数在一个ajax请求完成时会被触发,不管这个请求成功与否。 这里我们设置了30秒的超时,如果服务器在30内响应,我们的回调函数就会执行(比如聊天室更新聊天记录什么的),然后回调complete函数,如果响应超时,同样会回调complete函数,我们在complete这里执行了函数体本身,以上过程周而复始,这样就能保持与服务器的长久连接了,但是问题来了,
如果我们要终止长轮询该怎么做?
如果页面发生了跳转,代码自然就不会再继续执行,但是如果没有跳转呢?经过探索,代码变成了这样
poll = (method, url, data, callback) ->
if jQuery.isFunction data
callback = data
data = {}
_poll = ->
jQuery.ajax url,
type: method,
dataType: "json",
data: data,
timeout: 30000
success: (o) ->
callback and callback(o)
error: (xhr, msg, e) ->
if msg == "timeout"
_poll()
(xhr = poll "get", "/", (o) ->
if o.success
console.log o
else
xhr()
)()
这里poll会返回一个函数,函数执行时开始进行ajax请求,如果服务器在超时前响应了,我们会根据服务器的响应内容决定是否继续发请求,如果超时了,error函数会被回调,请求会继续发,直到地(wang)久(ye)天(guan)荒(bi)。到这里,我们已经很好的实现了预期的功能。
注意:
- error的触发可能是timeout以外的事件
- 超时时间理论上越长越好,但是30秒是个安全值,你可以在客户端设置30秒超时,服务器在27秒的时候响应
参考文章:
http://xmpp.org/internet-drafts/attic/draft-loreto-http-bidirectional-00.html#timeouts