惰性函数实现高性能能力检测

在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);
};

能够看到实现的方式异常简单,经过对方法的重载,并在初始执行时手动执行重载后的方法,知足了咱们上述的条件。

结束语

可能你们会说,你个标题党,最后一种重载的方式才是相对完美的方式,今天又为何要讲惰性函数呢?无外,抛砖引玉罢了,在钻研设计模式时,是绝对离不开闭包和惰性函数的,今天则算是小小的热身。

相关文章
相关标签/搜索