出處:http://www.cnblogs.com/GerryOfZhong/p/6135288.html
作者:半個(gè)詩(shī)人
上一篇(框架基礎(chǔ):ajax設(shè)計(jì)方案(一)---集成核心請(qǐng)求)文章介紹了ajax技術(shù)核心方法凳枝,和跨域的問題(只要后臺(tái)支持跨域默認(rèn)post就可以)跋核,這篇文章講解一下使用ajax實(shí)現(xiàn)的輪詢技術(shù),至于iframe蹋订,SSE服務(wù)器單向推送刻伊,以及webSocket雙工通道暫時(shí)不涉及。
一些概念:
- 短輪詢:瀏覽器通過循環(huán)或者setTimeout方法智什,每隔一段時(shí)間往后臺(tái)發(fā)送一次請(qǐng)求讼呢,無(wú)線循環(huán)
- 長(zhǎng)輪詢:不停的向后臺(tái)請(qǐng)求數(shù)據(jù)悦屏,但是后臺(tái)如果檢測(cè)不到數(shù)據(jù)變動(dòng)键思,就會(huì)將這個(gè)請(qǐng)求掛掉甫贯。如果檢測(cè)到數(shù)據(jù)變動(dòng),就會(huì)響應(yīng)這個(gè)請(qǐng)求變動(dòng)數(shù)據(jù)
區(qū)別概念:
- 長(zhǎng)連接:在進(jìn)行http數(shù)據(jù)傳輸?shù)臅r(shí)候赔桌,在數(shù)據(jù)傳輸層一直開著一個(gè)TCP通道渴逻,所有請(qǐng)求資源文件都是通過復(fù)用這個(gè)通道去請(qǐng)求數(shù)據(jù),有超時(shí)時(shí)間
- 短連接:如果http進(jìn)行的短連接雪位,即每次瀏覽器發(fā)送請(qǐng)求梨撞,都會(huì)創(chuàng)建TCP通道,然后傳輸完成了再進(jìn)行銷毀时肿,重復(fù)操作港粱,消耗很大
主要區(qū)別:
- http的長(zhǎng)短輪詢,通過代碼層锈颗,向后臺(tái)請(qǐng)求數(shù)據(jù)咪惠。
- http的長(zhǎng)短連接淋淀,實(shí)際上就是TCP協(xié)議傳輸層是否復(fù)用一個(gè)TCP協(xié)議朵纷。
主要業(yè)務(wù)方面:及時(shí)性比較高的應(yīng)用(web端聊天系統(tǒng)),或者需要后臺(tái)等待響應(yīng)的應(yīng)用(比如付款鞋仍,等待完成響應(yīng))搅吁。
關(guān)鍵代碼:
/*
* 長(zhǎng)輪詢的實(shí)現(xiàn)
* a. 業(yè)務(wù)上只需要得到服務(wù)器一次響應(yīng)的輪詢
* b. 業(yè)務(wù)上需要無(wú)限次得到服務(wù)器響應(yīng)的輪詢
*
* param: url 請(qǐng)求接口地址
* data 請(qǐng)求參數(shù)
* successEvent 成功事件處理
* isAll 是否一直請(qǐng)求(例如落午,等待付款完成業(yè)務(wù)溃斋,只需要請(qǐng)求一次)
* timeout ajax超時(shí)時(shí)間
* timeFrequency 每隔多少時(shí)間發(fā)送一次請(qǐng)求
* error 錯(cuò)誤事件
* timeout 超時(shí)處理
* */
longPolling:function(url,data,successEvent,isAll,timeout,timeFrequency,errorEvent,timeoutEvent){
var ajaxParam ={
time:timeout,
type:"post",
url:url,
data:data,
async:false,
success:function(date){
successEvent(data);
var timer = setTimeout(
function(){
tempObj.longPolling(url,data,successEvent,isAll,error,timeoutEvent);
},timeFrequency);
//業(yè)務(wù)需求判斷吸申,是否只需要得到一次結(jié)果
if (!isAll) clearTimeout(timer);
},
//如果走了error說明該接口有問題,沒必要繼續(xù)下去了
error:errorEvent,
timeout:function(){
timeoutEvent();
setTimeout(function(){
tempObj.longPolling(url,data,successEvent,isAll,error,timeoutEvent)
},timeFrequency);
}
};
ajax.common(ajaxParam);
}
考慮到業(yè)務(wù)需求梳侨,集成了一次isAll參數(shù)有2個(gè)意義
聊天系統(tǒng)會(huì)要一直需求輪詢走哺,不間斷的向后臺(tái)使用數(shù)據(jù)聚凹,所以isAll = true
等待付款業(yè)務(wù)只需要得到后臺(tái)一次響應(yīng)是否支付成功,所以isAll = false
稍微提及一下遇到的一些問題:
問題:
success:function(date){
successEvent(data); //此處使用遞歸彼哼,不停遞歸自己
tempObj.longPolling(url,data,successEvent,isAll,error,timeoutEvent);
},
瀏覽器報(bào)錯(cuò):
Uncaught RangeError: Maximum call stack size exceeded.
at Object.common (ajax-1.2.js:202)
at Object.longPolling (ajax-1.2.js:280)
at Object.success (ajax-1.2.js:266)
at XMLHttpRequest.xhr.onload (ajax-1.2.js:160)
at Object.common (ajax-1.2.js:202)
at Object.longPolling (ajax-1.2.js:280)
at Object.success (ajax-1.2.js:266)
at XMLHttpRequest.xhr.onload (ajax-1.2.js:160)
at Object.common (ajax-1.2.js:202)
at Object.longPolling (ajax-1.2.js:280)
common @ ajax-1.2.js:202
longPolling @ ajax-1.2.js:280
success @ ajax-1.2.js:266
xhr.onload @ ajax-1.2.js:160
(anonymous) @ index.html:42
(anonymous) @ index.html:43
ajax-1.2.js:202 Uncaught RangeError: Maximum call stack size exceeded.
at Object.common (ajax-1.2.js:202)
at Object.longPolling (ajax-1.2.js:280)
at Object.success (ajax-1.2.js:266)
at XMLHttpRequest.xhr.onload (ajax-1.2.js:160)
at Object.common (ajax-1.2.js:202)
at Object.longPolling (ajax-1.2.js:280)
at Object.success (ajax-1.2.js:266)
at XMLHttpRequest.xhr.onload (ajax-1.2.js:160)
at Object.common (ajax-1.2.js:202)
at Object.longPolling (ajax-1.2.js:280)
英文解釋:
超出最大調(diào)用堆棧大小敢朱。
問題原因:
遞歸調(diào)用過多導(dǎo)致的棧溢出問題說明
問題解釋:
函數(shù)調(diào)用的參數(shù)是通過椖ο梗空間來傳遞的,在調(diào)用過程中會(huì)占用線程的棧資源蚓哩。而遞歸調(diào)用上渴,只有走到最后的結(jié)束點(diǎn)后函數(shù)才能依次退出,而未到達(dá)最后的結(jié)束點(diǎn)之前曹阔,占用的椄襞空間一直沒有釋放,如果遞歸調(diào)用次數(shù)過多抓韩,就可能導(dǎo)致占用的棧資源超過線程的最大值,從而導(dǎo)致棧溢出园蝠,導(dǎo)致程序的異常退出彪薛。js可以調(diào)用自身,這里不停的調(diào)用longPolling方法少态,在方法里面不停的調(diào)用自己易遣,導(dǎo)致GC(垃圾回收)一直不釋放,越來越大侨歉,導(dǎo)致資源超過最大上限揩魂,直接崩潰。然后級(jí)聯(lián)一層一層的拋出崩潰信息
解決方案:
使用settimeout解決該問題
方案解釋:
因?yàn)镴avascript是單線程的牵舵,有個(gè)排隊(duì)的處理隊(duì)列倦挂,所以settimeout相當(dāng)于有一個(gè)計(jì)時(shí)器,不停的向這個(gè)隊(duì)列每隔一段時(shí)間塞進(jìn)一個(gè)處理事件没炒。因?yàn)檫@樣犯戏,相當(dāng)于longPolling方法每次都走完了,GC就將該方法的資源釋放了,然后再執(zhí)行假颇,再釋放笨鸡。
代碼已集成github:GerryIsWarrior/ajax坦冠,點(diǎn)顆星星是我最大的鼓勵(lì)哥桥,下一步研究ajax的上傳文件技術(shù)(H5的)
PS:對(duì)于輪詢這個(gè)技術(shù),雖然平時(shí)用的少判呕,但是在一些特殊的業(yè)務(wù)場(chǎng)景能發(fā)揮很大的作用送滞。在瀏覽器,沒有完完全全支持H5的境況下边涕,這個(gè)還是要考慮的褂微。畢竟H5的那些webSocket還是需要H5兼容的。而且式撼,研究這一塊肥矢,對(duì)原聲js甘改,和計(jì)算機(jī)的一些底層技術(shù)還是很有幫助的,像堆棧溢出十艾,不僅僅是前端,后端也會(huì)遇到忘嫉。這樣的話庆冕,自己底層更夯實(shí),對(duì)于以后上層的發(fā)展也會(huì)有更好的增長(zhǎng)访递。
本文完!
在學(xué)習(xí)過程如果有任何疑問惭载,請(qǐng)來極樂網(wǎng)(http://www.dreawer.com提問描滔,或者掃描下方二維碼,關(guān)注極樂官方微信券腔,在平臺(tái)下方留言~
