Note On <High Performance JavaScript> - 03

85 篇文章 0 订阅
58 篇文章 0 订阅

Chapter 8: 实践技巧


避免双重执行

这个部分讨论的是动态执行的JS代码,通过eval(),Function(),setTimeout()和setInterval()所创建的代码都会经过两次执行的过程,而这导致它们慢很多。


作者的建议是,对于eval()和Function()最好是索性直接避免,而后两者setTimeout()和setInterval(),可以传递预先定义的函数。


====================================================================


使用字面定义

这个问题至少David在【Effective JavaScript】里说过。简单讲就是:

//create an object
var myObject = new Object();
myObject.name = "Nicholas";
myObject.count = 50;
myObject.flag = true;
myObject.pointer = null;
//create an array
var myArray = new Array();
myArray[0] = "Nicholas";
myArray[1] = 50;
myArray[2] = true;
myArray[3] = null;

不如下面执行效率高:

//create an object
var myObject = {
    name: & quot;Nicholas & quot;,
    count: 50,
    flag: true,
    pointer: null
};
//create an array
var myArray = [ & quot;Nicholas & quot;, 50, true, null];


====================================================================


不要重复执行做过的事情

这个部分的例子很经典,判断浏览器和版本,决定执行怎样的代码,通常的写法可能会是:

function addHandler(target, eventType, handler) {
    if (target.addEventListener) { //DOM2 Events
        target.addEventListener(eventType, handler, false);
    } else { //IE
        target.attachEvent("on" + eventType, handler);
    }
}

function removeHandler(target, eventType, handler) {
    if (target.removeEventListener) { //DOM2 Events
        target.removeEventListener(eventType, handler, false);
    } else { //IE
        target.detachEvent("on" + eventType, handler);
    }
}


这里判断浏览器的逻辑被重复了。有两个解决方案:


慵懒加载

function addHandler(target, eventType, handler) {
    //overwrite the existing function
    if (target.addEventListener) { //DOM2 Events
        addHandler = function(target, eventType, handler) {
            target.addEventListener(eventType, handler, false);
        };
    } else { //IE
        addHandler = function(target, eventType, handler) {
            target.attachEvent("on" + eventType, handler);
        };
    }
    //call the new function
    addHandler(target, eventType, handler);
}

function removeHandler(target, eventType, handler) {
    //overwrite the existing function
    if (target.removeEventListener) { //DOM2 Events
        removeHandler = function(target, eventType, handler) {
            target.addEventListener(eventType, handler, false);
        };
    } else { //IE
        removeHandler = function(target, eventType, handler) {
            target.detachEvent("on" + eventType, handler);
        };
    }
    //call the new function
    removeHandler(target, eventType, handler);
}

在一个函数体自身内重新定义该函数,厉害呀!适用于并非在页面加载完成后马上要执行的功能。


条件性预先加载

var addHandler = document.body.addEventListener ?
    function(target, eventType, handler) {
        target.addEventListener(eventType, handler, false);
    } :
    function(target, eventType, handler) {
        target.attachEvent("on" + eventType, handler);
    };
var removeHandler = document.body.removeEventListener ?
    function(target, eventType, handler) {
        target.removeEventListener(eventType, handler, false);
    } :
    function(target, eventType, handler) {
        target.detachEvent("on" + eventType, handler);
    };

适用于页面加载后要立即执行的功能。


====================================================================


使用执行效率最高的方法


位操作符

在基于32位二进制表达上进行的位运算是最快的,而且其实JS支持这些位操作符:&, |,^和~,甚至>>,<<和>>>。


比如下面的代码:

for (var i = 0, len = rows.length; i < len; i++) {
    if (i % 2) {
        className = "even";
    } else {
        className = "odd";
    }
    //apply class
}

换成下面的方案后执行起来会快很多:

for (var i = 0, len = rows.length; i < len; i++) {
    if (i & 1) {
        className = "odd";
    } else {
        className = "even";
    }
    //apply class
}


另外还有个位掩码(bitmask)的方案也很经典,这个我曾经在SQL的层面用过:

var OPTION_A = 1;
var OPTION_B = 2;
var OPTION_C = 4;
var OPTION_D = 8;
var OPTION_E = 16;
var options = OPTION_A | OPTION_C | OPTION_D;
//is option A in the list?
if (options & OPTION_A) {
    //do something
}
//is option B in the list?
if (options & OPTION_B) {
    //do something
}


原生态方法

就像Math这种內建对象的方法比如Math.acos(x)其实都是在更低的层面上实现的,会快很多。


还有查找DOM元素的两个方法:querySelector()和querySelectorAll()。


Chapter 9: 构建与配置高性能的JavaScript应用程序


这一章讲的东西跟写代码没有直接关系。是在构建大型项目时会用到的构建工具和一些用于优化性能的工具。


这些工具可以做的事情包括:

  • 把若干个JS文件整合成一个JS文件;
  • 有条件性地插入一些代码,比如根据不同开发阶段插入不同用于调试的代码;
  • 修改新版本文件名来解决缓存技术导致的文件更新问题;
  • 上传新版文件至远端服务器,类似CDN;
  • 等等

作者是以Ant为例子展示这些动能的,不过近年来貌似没有人再用Ant了,完全没有听人讨论过。


其他的相关工具和方法还包括:

  • 给JS文件瘦身,用类似YUI Compressor和Packer这样的工具;
  • 在服务器端开启压缩功能,使用gzip这样的编码格式传输文件;
  • 缓存JS文件,避免多余的HTTP请求,
  • 使用CDN这样的分布式工具;
  • 等等。


最后作者推荐一个Yahoo自己的工具:smasher,它能完成大多数上面提到的功能。


Chapter 10: 工具

这一章介绍的工具主要用于两个方面,分析JS程序的性能,和分析页面加载过程的瓶颈。


值得注意的是,有些优化性能的方案是受限于浏览器的,它或许反而导致在其他浏览器上效率变差。


分析性能

YUI Profiler

匿名函数

为了配合性能分析工具,最好还是不要使用匿名函数,而且内联呼叫也不如显式地赋值函数再调用。


比如下面的写法:

myNode.onclick = function() {
    myApp.loadData();
};

不如换做:

myApp._onClick = function() {
    myApp.loadData();
};
myNode.onclick = myApp._onClick;


寻找被阻滞的脚本文件

Page Speed

依然在发展中。

Fiddler

这个我一直有用。


YSlow

从项目的Git主页来看,最后一次更新是在2014年三月,也就是说它的开发已经被停止三年了,等同于被抛弃的项目。

dynaTrace Ajax Edition

这个工具不是免费的。


顺藤摸瓜找到的一些链接:

15 Website Speed Test Tools for Analyzing Web Performance

Must See JavaScript Dev Tools That Put Other Dev Tools to Shame




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值