高性能Javascript笔记

.) 下载并执行javacript会阻塞页面渲染,因此比较推荐js脚本放在页面底部,在</body>标签上边...
.) 尽量减少script标签。如果外链多个script文件,能合并就合并(利用合并的工具),同样适用内嵌的。
.) 动态脚本加载,无阻塞的比较好的解决方案:创建script DOM
比如:

var script = document.createElement("script");
script.type = "text/javascript";
//Firefox, Opera, Chrome, Safari 3+ 
//js文件src下载完的触发事件
script.onload = function(){
  alert(1);
};
script.src = "jquery.js";
document.getElementsByTagName("head")[0].appendChild(script);

 

.) 另一种无阻塞载入,利用xhr对象获取脚本注入,这种方法不能跨域获取(--ajax

 var xhr = new XMLHttpRequest();
    xhr.open("get", "file1.js", true);
    xhr.onreadystatechange = function(){
        if (xhr.readyState == 4){
            if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
                var script = document.createElement ("script");
                script.type = "text/javascript";
                script.text = xhr.responseText;// 相当于内联聊本的<script>标签
                document.body.appendChild(script);
            }
        }
    };
    xhr.send(null);

 

事件委托:

dom如下所示,

span上都要有点击事件的反馈。如果在每个span上绑定click事件的话,当li很多时候,这样比较浪费性能。
事件绑定占用了处理时间,浏览器需要跟踪每个事件处理器,占用了更多内存。
此时可以使用事件委托。利用冒泡机制,在其父节点,比如只需要在ul上监听一个点击事件。然后判断节点哪个是哪个就ok了。

<div>
    <ul id="ul">
        <li>
            <span id="a">aaaaa</span>
        </li>
        <li>
            <span id="b">bbbb</span>
        </li>
        <li>
            <span id="c">ccccc</span>
        </li>
        <li>
            <span id="d">ddddd</span>
        </li>
    </ul>
</div>

<script type="text/javascript">
    $('#ul').click(function(e){
            var target = e.target;
           // 只有点击的是span标签才触发事件
            if(target.nodeName.toLowerCase() != 'span'){
                return false;
            }
            var id = target.id; // 判断目标对象是哪个span
            switch(id){
                case 'a': alert(1);break;
                case 'b': alert(2);break;
                case 'c': alert(3);break;
                case 'd': alert(4);break;
            }

        });
</script>        

 

 

 

字符串连接;

str += "one" + "two";

str += "one";
str += "two";

str = str + "one" + "two";

第一行代码比较浪费,内存需要分配一个临时字符串来连接 "onetwo",然后再连str。

剩下两种方式,则不需要内存额外分配变量。

 

 

作用域链和原型链得知,一个全局变量在局域使用,最好是赋值给局域变量。链上远的变量查找更耗时,更消耗性能。

 

在操作dom集合(类数组而不是数组)的时候,涉及到length,尽量把这个集合的length赋值给一个变量,然后在循环里使用这个变量。遍历集合没有遍历数组快。

 

大多数时候没必要使用eval()和Function(),每次调用eval()时都要创建一个新的解释器/编译器示例。
尽量避免使用他们。至于setTimeout()和setInterval(),建议传入函数而不是字符串作为第一个参数。比如:

setTimeout(function(){
    sum = a+b;
}, 100);

 

使用Object/Array时,建议使用直接量,这样更快。
比如:

var obj = new Object();
obj.name = 'a';
obj.age = 12;

// 更推荐这种方式:
var obj = {
name: 'a',
age: 12
};

// ============
// 数组比如:
var arr = new Array();
arr[0] = 'a';
arr[1] = 'b';

// 更推荐这种:
var arr = ['a', 'b'];

 

不要重复工作:
比如根据一个判断(比如这里的 a 和 b 大小比较)处理一个逻辑:

var a=1;
var b=2;
function test(){
    if(b>a){
       xxx;// 几行代码
    } else {
       yyy;//
    }
}

比如这个 test() 函数在页面上可能会频繁遭到调用,那么每次都要去判断 a 和 b 的大小(如果是更复杂的逻辑判断,那么频繁调用一定会浪费性能)。那么不如在代码中重新覆盖这个 test() 函数:

function test(){
    if(b>a){
       test = function(){// 重新给test赋值
           xxx;
        };
    } else {
        test = function(){
           yyy;
        };
    }
    test();// 当然结尾不要忘记执行
}          

 

这样的话,下一次再去调用这个test()的话,直接就是了。


数字运算的话,可以多考虑下,是否可以按位运算。比如奇数偶数这个...和1按位与操作。

尽量使用原生js,比较原生的都是js引擎低级编程语言编译好的,要更快。

 


Ajax:

常用的向服务器请求数据的方法:
1. XMLHttpRequest(XHR) 最常用的技术
2. 动态脚本注入
3. Multipart XHR

1). xhr(ajax常用技术,IE低版本要使用 ActiveXObject )是最常用的,它允许异步发送和接收数据。浏览器支持好,get、post方式均可,可以读取http响应头信息和响应文本。缺点不能跨域。
代码:

var url = '/data.php?a=1&b=2';
var req = new XMLHttpRequest();

req.onreadystatechange = function(){
    if(req.readyState === 4){// 4表示整个响应接收完毕;3表示接收到部分信息,还没完
        var responseHeaders = req.getAllResponseHeaders();// 获取响应头信息
        var data = req.responseText;// 获取响应文本
        // 逻辑处理
        // ...
    }
}

req.open('GET', url, true);// true表示异步
req.setRequestHeader('', '');// 可以设置请求头信息
req.send(null);// 发送请求

 

2). 动态脚本注入
这个方法利用动态创建 script 元素来请求数据。它克服了xhr最大限制:可以跨域请求。这当然算是个Hack。

xhr的缺点:不可以设置请求头信息;也只能使用get方式;需要等这个脚本下载完,才能访问它们;返回的数据需要封装在函数里。
因为响应信息是脚本标签的源码(script),因此他必须是可执行的javascript代码,所以数据格式需要封装在函数里,或者说调用一个函数。
代码:

var scriptEle = document.createElement('script');
scriptEle.src = 'http://xxx/test.js';// 可以请求与当前脚本所在不同域的文件。
document.getElementsByTagName('head')[0].appendChild(scriptEle); // 在head头部插入脚本
function callfun(data){
    // 接收到服务端过来的 data
    alert(data.a);
}


// test.js 文件内容
callfun({a:1,b:'qq'});// 数据被包含在回调函数里。

 

 

向服务器传输数据:
一种xhr的技术,还有一种信标的方法。
所谓信标,就是创建一个Image对象,利用属性src向服务器传输数据。然而这种方法,效率虽高,但是存在局限性,一般只是像服务器传输数据,而不关心返回结果(当然服务端的确可以返回一个图片,然后前端根据图片的比如宽度来判断逻辑,这个宽度也可以算是服务端的返回状态。不过一般使用这种方法,不考虑服务端返回结果...),而且src表示也只能以get方式传输,并且参数长度也有所限制。
代码:

(new Image()).src = 'http://www.test.com/xxx.php?a=1&b=x';// 传输了a、b两个参数值过去

 

 

-

posted @ 2016-04-21 18:43  根号五  阅读(385)  评论(0编辑  收藏  举报