javascript效能優化(7)

Presbyterian發表於2018-03-14

Ajax 非同步 JavaScript 和 XML

Ajax 是高效能 JavaScript 的基石。它可以通過延遲下載大量資源使頁面載入更快。它通過在客戶端和服 務器之間非同步傳送資料,避免頁面集體載入。它還用於在一次 HTTP 請求中獲取整個頁面的資源。通過選 擇正確的傳輸技術和有效的資料格式,你可以顯著改善使用者與網站之間的互動。

資料傳輸

有5種常用的技術用於向伺服器請求資料:

  1. XMLHttpRequest (XHR)
  2. Dynamic script tag insertion 動態指令碼標籤插入
  3. iframes
  4. Comet
  5. Multipart XHR 多部分的 XHR
    現在常使用的三種技術是XHR、動態指令碼標籤插入、多部分的 XHR ;剩餘兩種就不做討論。

XMLHttpRequest

    var url = '/data.php';
    var params = ['id=934875', 'limit=20'];
    var req = new XMLHttpRequest();
    req.onreadystatechange = function () {
     if (req.readyState === 3) { // Some, but not all, data has been received.     
             // Process the data here... 
         }
        else if (req.readyState === 4) {
            var responseHeaders = req.getAllResponseHeaders(); // Get the response headers.     
            var data = req.responseText; // Get the data.     
            // Process the data here...   
        }
    }
    req.open('GET', url + '?' + params.join('&'), true);
    req.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); // Set a request header. 
    req.send(null); // Send the request.

readyState 等於3 “ ”,表示此時正在與伺服器互動,響應報文還在傳輸中。這就是所謂的“流”,他是提高資料請求效能的強大工具。readyState 等於4,表示整個響應報文已經收並完,可用於操作。

使用 POST,還是 GET

如果請求不改變伺服器狀態只是取回資料,則用get;get請求被緩衝起來,如果你多次提取相同的資料可提高效能。
只有當URL和引數的長度超過了2048個字元時才使用POST提取資料;因為IE限制URL的長度,過長將導致請求引數被截斷。

動態指令碼標籤插入

    var scriptElement = document.createElement('script');
    scriptElement.src = 'http://any-domain.com/javascript/lib.js';
    document.getElementsByTagName('head')[0].appendChild(scriptElement);

在lib.js檔案中,將呼叫jsonCallback函式組裝資料;

     function jsonCallback(jsonString) {
        var data = ('(' + jsonString + ')');
        // Process the data here... 
    }

    jsonCallback({"status": 1, "colors": ["#fff", "#000", "#ff0000"]});

Multipart XHR 多部分XHR

多部分 XHR(MXHR)允許你只用一個 HTTP 請求就可以從伺服器端獲取多個 資源。它通過將資源(可以是 CSS 檔案,HTML 片段,JavaScript 程式碼,或 base64 編碼的圖片)打包成一 個由特定分隔符界定的大字串,從伺服器端傳送到客戶端。JavaScript 程式碼處理此長字串,根據它的 媒體型別和其他“資訊頭”解析出每個資源.

由於 MXHR 響應報文越來越大,有必要在每個資源收到時立刻處理,而不是等待整個響應報文接收完 成。這可以通過監聽 readyState 3 實現: 
        var req = new XMLHttpRequest();
        var getLatestPacketInterval, lastLength = 0;
        req.open('GET', 'rollup_images.php', true);
        req.onreadystatechange = readyStateHandler;
        req.send(null);
     function readyStateHandler (){
        if (req.readyState === 3 && getLatestPacketInterval === null) {     // Start polling.
            getLatestPacketInterval = window.setInterval(function () {
                getLatestPacket();
            }, 15);
        }
        if (req.readyState === 4) {     // Stop polling.
            clearInterval(getLatestPacketInterval);     // Get the last packet.
            getLatestPacket();
        }
    }
    function getLatestPacket() {
        var length = req.responseText.length;
        var packet = req.responseText.substring(lastLength, length);
        processPacket(packet);
        lastLength = length;
    }

當 readyState 3 第一次發出時,啟動了一個定時器。每隔 15 毫秒檢查一次響應報文中的新資料。資料片 段被收集起來直到發現一個分隔符,然後一切都作為一個完整的資源處理.

缺點:

  • 資源不能被瀏覽器快取。
  • 老版本的 Internet Explorer 不支援 readyState 3 或 data: URL。Internet Explorer 8 兩個都支 持,但在 Internet Explorer 6 和 7 中必須設法變通。

傳送資料

當使用 XHR 將資料發回伺服器時,它比使用 GET 要快。這是因為對少量資料而言,向伺服器傳送一個 GET 請求要佔用一個單獨的資料包。另一方面,一個 POST 至少傳送兩個資料包,一個用於資訊頭。另一 個用於 POST 體。POST 更適合於向伺服器傳送大量資料,即因為它不關心額外資料包的數量,又因為 Internet Explorer 的 URL 長度限制,它不可能使用過長的 GET 請求。

資料格式

這裡只看了JSON,JSONP;其他的像XML等,不做分析。
常見的json格式

[   
 {"id":1, "username":"alice", "realname": "Alice Smith", "email":"alice@alicesmith.com"},
 {"id":2, "username":"bob", "realname": "Bob Jones", "email":"bob@bobjones.com"}, 
 {"id":3, "username":"carol", "realname": "Carol Williams","email":"carol@carolwilliams.com"},  
 {"id":4, "username":"dave", "realname": "Dave Johnson", "email":"dave@davejohnson.com"} 
] 

陣列格式的json

[  
 [ 1, "alice", "Alice Smith", "alice@alicesmith.com" ],
 [ 2, "bob", "Bob Jones", "bob@bobjones.com" ],  
 [ 3, "carol", "Carol Williams", "carol@carolwilliams.com" ],  
 [ 4, "dave", "Dave Johnson", "dave@davejohnson.com" ] 
] 

陣列形式的 JSON 在每一項中均獲勝,它檔案尺寸小,下載快,平均解析時間短。儘管解析函式 不得不遍歷列表中所有 5’000 個單元,它還是快出了 30%。
避免使用 JSON-P的原因:因為 JSON-P 必須是可執行的 JavaScript,它使用動態 指令碼標籤注入技術可在任何網站中被任何人呼叫。從另一個角度說,JSON 在執行之前並不是有效的 JavaScript,使用 XHR 時只是被當作字串獲取。不要將任何敏感的資料編碼為 JSON-P,因為你無法確定 它是否包含私密資訊,或者包含隨機的 URL 或 cookie。

資料格式總結

總的來說越輕量級的格式越好,好是 JSON 和字元分隔的自定義格式。如果資料集很大或者解析時間 成問題,那麼就使用這兩種格式之一:

  • JSON-P 資料,用動態指令碼標籤插入法獲取。它將資料視為可執行的 JavaScript 而不是字串,解析速度 極快。它能夠跨域使用,但不應涉及敏感資料。
  • 字元分隔的自定義格式,使用 XHR 或動態指令碼標籤插入技術提取,使用 split()解析。此技術在解析非常 大資料集時比 JSON-P 技術略快,而且通常檔案尺寸更小。
    這裡寫圖片描述
    下載和解析時間對比。

Ajax 效能嚮導

快取資料

快的 Ajax 請求就是你不要用它。有兩種主要方法避免發出一個不必要的請求:
1. 在伺服器端,設定 HTTP 頭,確保返回報文將被快取在瀏覽器中。
2. 在客戶端,於本地快取已獲取的資料,不要多次請求同一個資料。
第一種技術容易設定和維護,而第二個給你大程度的控制。

設定 HTTP 頭

在發起請求時使用 GET 方法。但這還不充分, 你必須在響應報文中傳送正確的 HTTP 頭。Expires 頭告訴瀏覽器應當快取響應報文多長時間.。其值是一個 日期,當過期之後任何對該 URL 發起的請求都不再從快取中獲得,而要重新訪問伺服器。一個 Expires 頭 如下:
Expires: Mon, 28 Jul 2014 23:30:00 GMT
Expires 頭中的日期是 GMT 日期。它在 PHP 中使用如下程式碼設定:

 $lifetime = 7 * 24 * 60 * 60; // 7 days, in seconds. 
 header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $lifetime) . ' GMT'); 
 //這將告訴瀏覽器快取此資料 7 天。

本地儲存資料

除了依賴瀏覽器處理快取之外,你還可以用手工方法實現它,直接儲存那些從伺服器收到的響應報文。 可將響應報文存放在一個物件中,以 URL 為鍵值索引它。這是一個 XHR 封裝,它首先檢查一個 URL 此 前是否被取用過,如果有直接調取之前的快取;沒有的話,就重新獲取。

 var localCache = {};
    function xhrRequest(url, callback) {   // Check the local cache for this URL.   
        if (localCache[url]) {
            callback.success(localCache[url]);
            return;
        }   // If this URL wasn't found in the cache, make the request.   
        var req = createXhrObject();
        req.onerror = function () {
            callback.error();
        };
        req.onreadystatechange = function () {
            if (req.readyState == 4) {
                if (req.responseText === '' || req.status == '404') {
                    callback.error();
                    return;
                }       // Store the response on the local cache.      
                localCache[url] = req.responseText;
                callback.success(req.responseText);
            }
        }
        ;
        req.open("GET", url, true);
        req.send(null);
    }

Summary 總結


  • 高效能 Ajax 包括:知道你專案的具體需求,選擇正確的資料格式和與之相配的傳輸技術。
  • 作為資料格式,純文字和 HTML 是高度限制的,但它們可節省客戶端的 CPU 週期。XML 被廣泛應用 普遍支援,但它非常冗長且解析緩慢。JSON 是輕量級的,解析迅速(作為原生程式碼而不是字串),交 互性與 XML 相當。字元分隔的自定義格式非常輕量,在大量資料集解析時速度快,但需要編寫額外的 程式在伺服器端構造格式,並在客戶端解析。
  • 當從頁面域請求資料時,XHR 提供完善的控制和靈活性,儘管它將所有傳入資料視為一個字串, 這有可能降低解析速度。另一方面,動態指令碼標籤插入技術允許跨域請求和本地執行 JavaScript 和 JSON, 雖然它的介面不夠安全,而且不能讀取資訊頭或響應報文程式碼。多部分 XHR 可減少請求的數量,可在一次響應中處理不同的檔案型別,儘管它不能快取收到的響應報文。當傳送資料時,影像燈標是簡單和有效的方法。XHR 也可用 POST 方法傳送大量資料。
    一些建議:

  • 減少請求數量,可通過 JavaScript 和 CSS 檔案打包,或者使用 MXHR。
  • 縮短頁面的載入時間,在頁面其它內容載入之後,使用 Ajax 獲取少量重要檔案。
  • 確保程式碼錯誤不要直接顯示給使用者,並在伺服器端處理錯誤。
  • 學會何時使用一個健壯的 Ajax 庫,何時編寫自己的底層 Ajax 程式碼。

相關文章