JS 对兼容性方法的效率考虑和选择

今天看书自己写例子,碰到了一个问题。

由于 Array.every 是 ECMAScript 5 定义的方法,需要 IE 9+、FireFox 2+、Opera 9.5+、Safari 3+ 和 Chrome* 的浏览器版本支持,在考虑到兼容性的时候需要兼容性写法:

// 定义方式 1
var
hs = { // 这是一个Array的工具类, 用以编写兼容性方法 ArrayUtil: { every: function(arr, func) { // 对参数的检测省略... if (Array.every) {  // 优先使用原生方法 return arr.every(func); } else {        // 否则使用兼容方法 var result = false; for(var i=0,len=arr.length; i<len; i++) { result = func(arr[i], i, arr); if (result === false) { return false; } } return true; } } // 其他兼容性方法省略... } }

这样就可以实现对低版本浏览器(比如IE6)的兼容。

 

但这种定义方式使得 every 方法存在一个问题,就是它在每次被调用执行的时候都会进行重复的判断——浏览器是否支持原生的 Array.every?浏览器是否支持原生的 Array.every?浏览器是否支持原生的 Array.every?……哪怕得到的永远是同一个答案……

如果这个兼容性方法只是偶尔调用,那重复的判断也不是什么大问题。

但如果这个方法被频繁调用,重复的判断造成的性能浪费就不能忽视了。

于是就有了下面的定义方式:

// 定义方式 2
var
hs = { ArrayUtil: { every: function() {    // 这是一个自调函数, 在(对象)方法创建之处就进行兼容性判断, 只保留一个选择,这个选择就构成了 every 方法的全部内容。 if (Array.every) { retrun function(arr, func) { return arr.every(func);      // 原来的执行代码被包裹在函数里, 而这个函数将被自调函数返回,并赋值给every。 }; } else { return function(arr, func) { var result = false; for(var i=0,len=arr.length; i<len; i++) { result = func(arr[i], i, arr); if (result === false) { return false; } } return true; }; } }() } }

这样,仅有的一次判断只会在对象(方法)创建时进行一次,every 保留唯一一个方法,在被调用执行时不会再进行重复而无意义的判断。

这种方式使程序变得更简洁、运行也更快速(哪怕只是一点,但这是量的积累)。

 

然而,它也不是全无缺点的,它的问题体现在代码首次加载(或程序初始化)的时候:

如果是个人网站、轻量代码,它“一步到位”的优点会显露无疑;

但在面对门户网这类大型网站、在面对大量代码(需要进行大量兼容性判断)的时候,它的“一次性”会让你的程序执行显得拖沓和吃力。

 

所幸这问题也不是无法避免的,我们可以对程序进行“分流”处理:对程序里的兼容性方法还是选用一次性判断的方式,但这“一次性”不再扎堆于程序初始化,而是分流于方法初次调用时——在方法被明确调用的时候才进行唯一一次判断。

// 定义方式 3
var hs = {

    ArrayUtil: {

        every: function(arr, func) {

            if (Array.every) {
                this.every = function(arr, func) {        // 重新赋值
                    return arr.every(func);
                };
            } else {
                this.every = function(arr, func) {        // 重新赋值
                    var result = false;

                    for(var i=0,len=arr.length; i<len; i++) {
                        result = func(arr[i], i, arr);
                        if (result === false) {
                            return false;
                        }
                    }

                    return true;
                };
            }
            return this.every(arr, func);                    // 方法第一次调用并重新赋值以后执行一次,确保这首次调用能有结果。
        }
    }
}    

这就解决了问题,只在方法被用到的时候才进行一次判断,不影响对象构建、程序初始化的速度。

相比于第二种方式,这种方式在第一次调用方法时也会损失一些性能,但就整个程序的性能来说,这已经是最佳选择。

 

三种定义方式各有优缺点,不同使用环境:

兼容性方法偶尔使用,选方式 1

兼容性方法频繁使用,但量少,选方式 2

兼容性方法频繁使用,且量大,选方式 3

另外,在各种情况下都能表现良好和稳妥的,是方式 3

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。