1. 程式人生 > >pace.js 原理(轉)

pace.js 原理(轉)

100% 處理 有趣的 所有 stat 請求 error 方法 並不會

pace.js監控了什麽:

pace.js對於加載進度監控了什麽呢?通過閱讀源碼,我們看到整體的進度有四個部分組成:document,elements,eventLag和ajax這四種監視器(Monitor)。

1.

那接下來就來看看它們分別是什麽。

首先是document。document就是我們所熟悉的HTMLDocument節點。document節點有一個事件,onreadystatechange,當document的readyState狀態變化時會觸發。因為無法準確的知道document到底加載了多少百分比,所以就用這個狀態來做一個估算。在pace.js中將document的readyState的三個狀態loadong,interactive和complete分別定義為0%,50%和100%。通過監聽document節點的readyState狀態變更,形成了pace.js的DocumentMonitor。

2.

接下來是elements。我們可以通過配置傳入一個css選擇器列表,默認的選擇器列表僅包含“body”。pace.js會按照設置的時間間隔搜索所有的選擇器,如果能獲得則認為這一項滿足,所以elements這一項的加載進度就是 滿足的選擇器/全部的選擇器。通過查詢頁面中制定的元素,就是pace.js的ElementMonitor。

3.

然後是eventLag。EventLagMonitor其實只是一個“假的”監視器。它就在那裏安靜勻速的更新進度,這一小小的措施卻帶來了不錯的用戶體驗,讓用戶不會因為加載“卡住了”而慌張。

pace.js是如何監控ajax的:

最後是用來監控ajax進度的AjaxMonitor。這是最有趣的一部分。如何才能監控所有ajax請求,並且不需要開發者修改自己或第三方的業務邏輯呢?

如果了解原生js的話,應該了解這幾個類:XMLHttpRequest,XDomainRequest,WebSocket。這三個類分別用來發送ajax請求,跨域的ajax請求,以及websocket。如果能監控所有這些請求的時間,包括progress,load,error等等,我們就可以更新我們的加載進度了。

既然我們知道了要監控的對象,那我們便可以“請君入甕”了,而這個甕,就是代理模式:我們可以把原生的類保存起來,再用我們自己寫的埋藏了“間諜”的類覆蓋原生的類,這樣當其他代碼建立這些類的實例的時候,我們的“間諜”便悄悄開始監聽加載進度了。

讓我們來看一下代碼:

// 保存原生的XMLHttpRequest
_XMLHttpRequest = window.XMLHttpRequest;

// 覆蓋XMLHttpRequest
window.XMLHttpRequest = function(flags) {
    var req;
    // 調用原生的XMLHttpRequest
    req = new _XMLHttpRequest(flags);
    // 埋入我們的“間諜”
    monitorXHR(req);
    return req;
};

monitorXHR = function(req) {
  var _open;
  // “間諜”又對open方法埋入了間諜
  _open = req.open;
  return req.open = function(type, url, async) {
    if (shouldTrack(type)) {
      _this.trigger(‘request‘, {
        type: type,
        url: url,
        request: req
      });
    }
    return _open.apply(req, arguments);
  };
};

通過代理模式埋了這些“間諜”後,我們就能對發起的ajax請求等做到監控,以更新加載進度。

當然pace.js也不是什麽都監聽了

除了以上這些,當然也有pace.js並沒有監聽的加載事件,比如script標簽的加載。如果我們使用了sea.js或者require.js等,當js代碼動態加載時並不會影響進度條,因為這裏我們用動態建立script標簽的方式加載js代碼,而pace.js並沒有對這方面進行監聽。我們可以同樣的代理appendChild方法,如果發現script標簽被加到頁面上,那麽就監聽它的加載進度。不過實際情況當然復雜的多,還有insertBefore,甚至innerHTML等方法都可以創建script標簽加入文檔並開始js的加載(當然一般就是appendChild和insertBefore啦)。

相似的還有css的加載,還要註意處理css的加載事件,在一些老的瀏覽器上,css並沒有加載事件,還有加個定時不斷檢查css節點的cssRules和name來確定加載狀況。

小結:

通過閱讀pace.js的源碼我們了解了pace.js的原理,同時學習了雞賊的代理模式。比如在jasmine.js中也有個spy,可以監控制定函數被調用了幾次,被什麽參數調用了等等。靈活應用這種代理模式,可以方便我們擴展功能、進行調試等等。

pace.js 原理(轉)