惰性函數實現高性能能力檢測

在SPA、各類MV*框架如日中天,先後端分離、工程化大行其道的現現在來看,能力檢測彷佛已經不那麼重要,由於大多產品已經再也不須要去兼容老舊的IE,或者說是更多偏向移動端的開發,雖然一些兼容的坑依舊存在,可是經過層出不窮的自動化工具,咱們已經沒必要事事躬親了。然而今天要向你們分享的則是關於事件兼容性的能力檢測,可能看上去沒什麼大的用場,倒是咱們理解惰性函數的好途徑。後端

常規的檢測方式

先看一則常見的事件監聽封裝設計模式

function addEvent(ele, type, cb, isCap) {
    
    if (window.addEventListener) {
        ele.addEventListener(type, cb, isCap);
    } else if (window.attachEvent) {
        ele.attachEvent(type, function () {
            var args            = [].prototype.slice(0);
            window.event[target] = window.event.srcElement;
            args.unshift(window.event);
            cb.apply(this, args);
        });
    } else {
        ele['on' + type] = cb;
    }

}

var body = document.body;

addEvent(body,'load',function () {
    console.log('onload') // onload
});

addEvent(body,'click',function () {
    console.log('onclick') // onclick
});

能夠看的到,這是一個有着足夠兼容性的的事件方法,可以應付常見的需求和場面。瀏覽器

只是細細想來,當咱們將這個方法複用了不少次後,會發現每次複用都會從新進行一次能力檢測,以便符合當前宿主環境。可能你會想,對於瀏覽器性能過剩的現現在來講,這點性能損耗並不算什麼。閉包

那麼不妨作個假設,當咱們在作一個高頻操做,例如window.onresize的監聽,鼠標隨便輕輕一拖,就可能會觸發無數次事件的重載。app

面臨這種情況,常規狀況下,有經驗的開發者大體會作兩種處理來改善性能。框架

  1. 函數節流,將方法限頻,過濾一些線性重複性的操做。這方面,在loadash和underscore都有相應的方法。往後我也會分享出原生的實現方式。
  2. 從源頭找起,把沒必要要的能力檢測去除,咱們只在頁面加載時檢測一次很差嗎?

惰性檢測方式

函數節流咱們往後再分享,那麼,要如何把沒必要要的能力檢測去除掉呢?下面有兩種實現方式,代碼以下:前後端分離

//使用惰性函數


var addEvent = (function () {
    //當即執行    
    if (window.addEventListener) {
        return function (ele, type, cb, isCap) {
            ele.addEventListener(type, cb, isCap);
        }
    } else if (window.attachEvent) {
        return function (ele, type, cb) {
            ele.attachEvent(type, function () {
                var args             = [].prototype.slice(0);
                window.event[target] = window.event.srcElement;
                args.unshift(window.event);
                cb.apply(this, args);
            });
        }
    } else {
        return function (ele, type, cb) {
            ele['on' + type] = cb;
        }

    //初始判斷事後,addEvent就無需再次判斷,已是正確的封裝。
    }
}());

代碼變化並不大,關鍵點在於,咱們用到了當即執行函數,即方法在初始化完畢,便當即判斷,判斷後,返回適合當前場景的方法。函數

//常見的方法調用方式
function getName() {
    console.log('ives')
}

getName() // ives;
//當即執行 能夠是聲明函數 也能夠是匿名函數 兩種方式都可
(function getName() {
    console.log('ives') // ives
}());

在常見的高階函數實踐中,咱們時常會接受函數,對函數的參數或者是上下文環境進行一些改造,並返回。在這種惰性判斷裏,咱們利用了函數一等公民的身份和當即執行的便利,進行了初始判斷,隨後經過return語句進行變量的重賦值,進而達到了性能上的提升。工具

實際上,不少經常使用的檢測,好比AJAX的封裝、獲取實際的CSS樣式等,均可以使用惰性函數處理。性能

重載檢測方式

然而,這種方法也並不是是完美的,咱們假設另一種場景,便是在靜態HTML中,咱們引用的某個JS文件中有這個方法,可是這個HTML頁面並無事件性質的交互,那麼咱們能夠基於吹毛求疵,雞蛋裏挑骨頭的角度來斷言,此次惰性加載是失敗的,無用的。由於咱們浪費了系統的資源,咱們沒有事件,你爲何要加載一次?

總而言之,惰性加載雖然性能有提高,卻仍然不是最好的處理,只是有利於咱們對於惰性函數的理解。

什麼情景纔是最完美的呢?便是初次調用時才作第一次判斷,隨後,無需判斷,方法也很簡單,只要簡單的改動幾行代碼。

依舊是以事件爲例,代碼以下:

var addEvent = function (ele,type,cb,isCap) {
    //取消了當即執行 初次調用時進行方法重載
    if (window.addEventListener) {
        addEvent = function (ele, type, cb, isCap) {
            ele.addEventListener(type, cb, isCap);
        }
    } else if (window.attachEvent) {
        addEvent = function (ele, type, cb) {
            ele.attachEvent(type, function () {
                var args             = [].prototype.slice(0);
                window.event[target] = window.event.srcElement;
                args.unshift(window.event);
                cb.apply(this, args);
            });
        }
    } else {
        addEvent = function (ele, type, cb) {
            ele['on' + type] = cb;
        }
    }
    //初次調用時,手動執行重載的方法
    addEvent(ele,type,cb,isCap);
};

能夠看到實現的方式異常簡單,經過對方法的重載,並在初始執行時手動執行重載後的方法,知足了咱們上述的條件。

結束語

可能你們會說,你個標題黨,最後一種重載的方式纔是相對完美的方式,今天又爲何要講惰性函數呢?無外,拋磚引玉罷了,在鑽研設計模式時,是絕對離不開閉包和惰性函數的,今天則算是小小的熱身。

相關文章
相關標籤/搜索