ajax和它的超時

日常開發中一般都會使得ajax去獲了數據,但有兩點是需要值得注意的:

1、ajax請求隊列

2、ajax的超時處理

爲什麼要注意這兩點?爲了讓用戶在其可視區域內更快速的看見內容。

假設頁面結構分爲三欄:左、中、右,而且頁面數據會比較多,頁面呈現的順序則是是按從上而下執行的(當然是從左至右開始,一個模塊一個模塊加載數據),如果不採用隊列,那麼在頁面可視範圍之外的模塊可能已經加載完數據了,而可視範圍之內(假設爲第一屏)的模塊卻尚未開始接收數據,這一類應用如:搜狐博客、新浪博客、網易博客等…

既然是採用了隊列,那麼又會有一個新的問題:需要保證一個請求的時候不能太長,不能因爲一個請求而導致後續的請求被阻塞了。在這兩點上jQuery做的其實都挺不錯的。隊列的處理上,已經有一個插件了,叫ajaxManager,例子和鏈接在這裏:http://www.protofunc.com/scripts/jquery/ajaxManager/;而在超時的處理上,jquery本身就支持傳遞參數timeout來進行設置(默認是沒有設置的)。它沒有考慮IE8,儘管IE已經支持xhr對象的timeout屬性。

從ajax創建開始,這裏優化的一點是針對IE瀏覽器,只循環獲取一次使用哪種MSXML庫,副作用就是需要使用額外的屬性來記錄它

function createXHR() {
    if (typeof XMLHttpRequest != 'undefined') {
        return new XMLHttpRequest();
    } else if (typeof ActiveXObject != 'undefined')    {
        if (typeof arguments.callee.activeXString != 'string') {
            var version = ["MSXML2.XMLHTTP.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];

            for (var i = 0, len = version.length; i < len; ++i) {
                try {
                    var xhr = new ActiveXObject(versions[i]);
                    arguments.callee.activeXString = versions[i];
                    return xhr;
                }
                catch (ex){

                }
            }
        }

        return new ActiveXObject(arguments.callee.activeXString);
    } else {
        throw new Error("No XHR object available.");
    }
}

創建的xhr對象,它對應有5狀態(readyState屬性)

0   Uninitialized(尚未調用open方法)

1   Loading (已調用open,尚未調用send)

2   Loaded (已經調用send,尚未接收到響應)

3   Interactive (開始接收數據)

4   Complete (數據接收完畢,響應內容解析完成)

在判定一個請求是否已經完成的時候,驗證xhr的status有一點是需要注意的:“有的瀏覽器會錯誤地返回204狀態碼”,而IE(非原生的XHR對象)中會將204設置爲1223,Opera會在取得204時將status設置爲0,而Safari 3之前的版本會將status設置爲undefined

最終驗證請求是否成功的代碼將會是:

 ( xhr.status >= 200 && xhr.status < 300 ) ||
 xhr.status === 304 || xhr.status === 1223 || xhr.status === 0 

另外在send的時候,還需要注意的是如果不需要通過請求主體發送數據,最好是傳入參數,因爲send方法的參數

對於有些瀏覽器是必需的,建議一般傳null即可

在發送請求時,可以通過setRequestHeader來設置HTTP頭部信息,在使用GET請求時,可以在頭部加上If-Modified-Since、Cache-Control參數來達到刷新緩存數據的目的(如果採用在URL上加隨機數據或是時間戳,資源並沒有被緩存)

 xhr.setRequestHeader('If-Modified-Since', 'Thu, 1 Jan 1970 00:00:00 GMT');
xhr.setRequestHeader('Cache-Control', 'no-cache'); 

在響應完成後,可以使用getResponseHeader、getAllResponseHeaders兩個方法來獲取指定或是全部的響應頭的HTTP信息

剩下的一個問題是,處理ajax超時的問題。jquery中的做法是使用定時器來檢測xhr的狀態,而使用延時器來解決超時的問題:

setInterval(onreadystatechange, 13);

setTimeout(fn, timeout);

而在自定義的onreadystatechange函數中會檢測傳入的參數,如果參數爲“timeout”則說明超時了,先調用xhr的abort取消請求,然後再調用complete方法。至於間隔時間爲什麼是13,這個沒仔細去研究它

正常情況下,如果readyState爲4,則先清除定時器,然後再檢測響應的數據。而setTimeout中的fn函數,在處理時會先檢測請求是否已經處理過了,這裏它並沒有對延時器進行引用,會導致的一種情況是,請求已經結束,延時器還在跑,直到達到指定的時間間隔。

最後如果ajax請求爲異步的話,別忘記將xhr置爲null==>xhr = null; 以防止內存泄漏的問題

IE8中直接寫xhr.timeout = xxx;然後當超時時,會調用xhr的ontimeout方法,不過需要注意的問題是,當調用ontimeout事件時,此時的readyState可能已經變爲了4,此時如果去訪問status則會導致錯誤(最好使用try{}catch{}進行捕獲一下)

到目前爲止,除IE外,其它瀏覽器支持xhr對象的onload事件,只要瀏覽器開始接收到響應,就會觸發它,所以在這個函數裏面還是需要對它的status屬性進行判斷。

最後一點是在FF 1.5之後,它支持progress事件,這意味着可以顯示當前請求的進度(不再是枯燥的loading了)。

在onprogress事件中會傳入一個event對象,它的target是對應的xhr對象,它包含了兩個額外的屬性:position、totalSize。

其中position表示已接收的字節數,totalSize表示根據Content-Length響應頭部確定的預期字節數。

 var xhr = new createXHR();
xhr.onload = function() {
    //...
}
xhr.onprogress = function(evt) {
    var percent = (evt.position / evt.totalSize)*100;
}
xhr.open("get", url, true);
xhr.send(null); 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章