前端通信:ajax設計方案(二)---集成輪詢技術


上一篇文章介紹了ajax技術核心方法,和跨域的問題(只要后台支持跨域默認post就可以),這篇文章講解一下使用ajax實現的輪詢技術,至於iframe,SSE服務器單向推送,以及webSocket雙工通道暫時不涉及

一些概念:

  短輪詢:瀏覽器通過循環或者setTimeout方法,每隔一段時間往后台發送一次請求,無線循環

  長輪詢:不停的向后台請求數據,但是后台如果檢測不到數據變動,就會將這個請求掛掉。如果檢測到數據變動,就會響應這個請求變動數據

區別概念:

  長連接:在進行http數據傳輸的時候,在數據傳輸層一直開着一個TCP通道,所有請求資源文件都是通過復用這個通道去請求數據,有超時時間

  短連接:如果http進行的短連接,即每次瀏覽器發送請求,都會創建TCP通道,然后傳輸完成了再進行銷毀,重復操作,消耗很大

 

主要區別:

  1. http的長短輪詢,通過代碼層,向后台請求數據。
  2. Http的長短連接,實際上就是TCP協議傳輸層是否復用一個TCP協議。

 

主要業務方面:及時性比較高的應用(web端聊天系統),或者需要后台等待響應的應用(比如付款,等待完成響應)。

關鍵代碼:

     /*
         * 長輪詢的實現
         *   a. 業務上只需要得到服務器一次響應的輪詢
         *   b. 業務上需要無限次得到服務器響應的輪詢
         *
         *   param: url   請求接口地址
         *          data  請求參數
         *          successEvent    成功事件處理
         *          isAll           是否一直請求(例如,等待付款完成業務,只需要請求一次)
         *          timeout         ajax超時時間
         *          timeFrequency   每隔多少時間發送一次請求
         *          error           錯誤事件
         *          timeout         超時處理
         * */
        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);
                    //業務需求判斷,是否只需要得到一次結果
                    if (!isAll) clearTimeout(timer);
                },
                //如果走了error說明該接口有問題,沒必要繼續下去了
                error:errorEvent,
                timeout:function(){
                    timeoutEvent();
                    setTimeout(function(){
                        tempObj.longPolling(url,data,successEvent,isAll,error,timeoutEvent)
                    },timeFrequency);
                }
            };
            ajax.common(ajaxParam);
        }

 

考慮到業務需求,集成了一次isAll參數有2個意義

  1. 聊天系統會要一直需求輪詢,不間斷的向后台使用數據,所以isAll = true
  2. 等待付款業務只需要得到后台一次響應是否支付成功,所以isAll = false

 

稍微提及一下遇到的一些問題:

問題

success:function(date){
     successEvent(data);
   //此處使用遞歸,不停遞歸自己 tempObj.longPolling(url,data,successEvent,isAll,error,timeoutEvent); },

瀏覽器報錯:

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)

 

英文解釋:

超出最大調用堆棧大小。

問題原因:

遞歸調用過多導致的棧溢出問題說明

問題解釋:

函數調用的參數是通過棧空間來傳遞的,在調用過程中會占用線程的棧資源。而遞歸調用,只有走到最后的結束點后函數才能依次退出,而未到達最后的結束點之前,占用的棧空間一直沒有釋放,如果遞歸調用次數過多,就可能導致占用的棧資源超過線程的最大值,從而導致棧溢出,導致程序的異常退出。js可以調用自身,這里不停的調用longPolling方法,在方法里面不停的調用自己,導致GC(垃圾回收)一直不釋放,越來越大,導致資源超過最大上限,直接崩潰。然后級聯一層一層的拋出崩潰信息

解決方案:

使用settimeout解決該問題

方案解釋:

因為Javascript是單線程的,有個排隊的處理隊列,所以settimeout相當於有一個計時器,不停的向這個隊列每隔一段時間塞進一個處理事件。因為這樣,相當於longPolling方法每次都走完了,GC就將該方法的資源釋放了,然后再執行,再釋放。

 

代碼已集成github:https://github.com/GerryIsWarrior/ajax     點顆星星是我最大的鼓勵,下一步研究ajax的上傳文件技術(H5的)

 

PS:對於輪詢這個技術,雖然平時用的少,但是在一些特殊的業務場景能發揮很大的作用。在瀏覽器,沒有完完全全支持H5的境況下,這個還是要考慮的。畢竟H5的那些webSocket還是需要H5兼容的。而且,研究這一塊,對原聲js,和計算機的一些底層技術還是很有幫助的,像堆棧溢出,不僅僅是前端,后端也會遇到。這樣的話,自己底層更夯實,對於以后上層的發展也會有更好的增長。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM