<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    zx_bing

    人生路漫漫,多學些知識總是有益處的
    隨筆 - 32, 文章 - 0, 評論 - 0, 引用 - 0
    數據加載中……

    提高js性能注意事項

    一.執行效率
    1. DOM
    1.1 使用DocumentFragment優化多次append
    說明:添加多個dom元素時,先將元素append到DocumentFragment中,最后統一將DocumentFragment添加到頁面。
    該做法可以減少頁面渲染dom元素的次數。經IE和Fx下測試,在append1000個元素時,效率能提高10%-30%,Fx下提升較為明顯。

    服用前:
    for (var i = 0; i < 1000; i++) {
        var el = document.createElement('p');
        el.innerHTML = i;
        document.body.appendChild(el);
    }

    服用后:
    var frag = document.createDocumentFragment();
    for (var i = 0; i < 1000; i++) {
        var el = document.createElement('p');
        el.innerHTML = i;
        frag.appendChild(el);
    }
    document.body.appendChild(frag);

    1.2 通過模板元素clone,替代createElement
    說明:通過一個模板dom對象cloneNode,效率比直接創建element高。
    性能提高不明顯,約為10%左右。在低于100個元素create和append操作時,沒有優勢。

    服用前:
    var frag = document.createDocumentFragment();
    for (var i = 0; i < 1000; i++) {
        var el = document.createElement('p');
        el.innerHTML = i;
        frag.appendChild(el);
    }
    document.body.appendChild(frag);   

    服用后:
    var frag = document.createDocumentFragment();
    var pEl = document.getElementsByTagName('p')[0];
    for (var i = 0; i < 1000; i++) {
        var el = pEl.cloneNode(false);
        el.innerHTML = i;
        frag.appendChild(el);
    }
    document.body.appendChild(frag);

    1.3 使用一次innerHTML賦值代替構建dom元素
    說明:根據數據構建列表樣式的時候,使用設置列表容器innerHTML的方式,比構建dom元素并append到頁面中的方式,效率有數量級上的提高。

    服用前:
    var frag = document.createDocumentFragment();
    for (var i = 0; i < 1000; i++) {
        var el = document.createElement('p');
        el.innerHTML = i;
        frag.appendChild(el);
    }
    document.body.appendChild(frag);

    服用后:
    var html = [];
    for (var i = 0; i < 1000; i++) {
        html.push('' + i + '
    ');
    }
    document.body.innerHTML = html.join('');

    1.4 使用firstChild和nextSibling代替childNodes遍歷dom元素
    說明:約能獲得30%-50%的性能提高。逆向遍歷時使用lastChild和previousSibling。

    服用前:
    var nodes = element.childNodes;
    for (var i = 0, l = nodes.length; i < l; i++) {
    var node = nodes[i];
    ……
    }

    服用后:
    var node = element.firstChild;
    while (node) {
    ……
    node = node.nextSibling;
    }


    2. 字符串

    2.1 使用Array做為StringBuffer,代替字符串拼接的操作
    說明:IE在對字符串拼接的時候,會創建臨時的String對象;經測試,在IE下,當拼接的字符串越來越大時,運行效率會急劇下降。Fx和Opera都對字符串拼接操作進行了優化;經測試,在Fx下,使用Array的join方式執行時間約為直接字符串拼接的1.4倍。

    服用前:
    var now = new Date();
    var str = '';
    for (var i = 0; i < 10000; i++) {
        str += '123456789123456789';
    }
    alert(new Date() - now);

    服用后:
    var now = new Date();
    var strBuffer = [];
    for (var i = 0; i < 10000; i++) {
        strBuffer.push('123456789123456789');
    }
    var str = strBuffer.join('');
    alert(new Date() - now);


    3. 循環語句

    3.1 將循環控制量保存到局部變量
    說明:對數組和列表對象的遍歷時,提前將length保存到局部變量中,避免在循環的每一步重復取值。

    服用前:
    var list = document.getElementsByTagName('p');
    for (var i = 0; i < list.length; i++) {
        ……
    }

    服用后:
    var list = document.getElementsByTagName('p');
    for (var i = 0, l = list.length; i < l; i++) {
        ……
    }


    3.2 順序無關的遍歷時,用while替代for
    說明:該方法可以減少局部變量的使用。比起效率優化,更能直接看到的是字符數量的優化。該做法有程序員強迫癥的嫌疑。

    服用前:
    var arr = [1,2,3,4,5,6,7];
    var sum = 0;
    for (var i = 0, l = arr.length; i < l; i++) {
        sum += arr[i];
    }   

    服用后:
    var arr = [1,2,3,4,5,6,7];
    var sum = 0, l = arr.length;
    while (l--) {
        sum += arr[l];
    }

    4. 條件分支

    4.1 將條件分支,按可能性順序從高到低排列
    說明:可以減少解釋器對條件的探測次數。

    4.2 在同一條件子的多(>2)條件分支時,使用switch優于if
    說明:switch分支選擇的效率高于if,在IE下尤為明顯。4分支的測試,IE下switch的執行時間約為if的一半。

    4.3 使用三目運算符替代條件分支
    服用前:
    if (a > b) {
    num = a;
    } else {
    num = b;
    }

    服用后:
    num = a > b ? a : b;


    5. 定時器

    5.1 需要不斷執行的時候,優先考慮使用setInterval
    說明:setTimeout每一次都會初始化一個定時器。setInterval只會在開始的時候初始化一個定時器

    服用前:
    var timeoutTimes = 0;
    function timeout () {
        timeoutTimes++;
        if (timeoutTimes < 10) {
            setTimeout(timeout, 10);
        }
    }
    timeout();

    服用后:
    var intervalTimes = 0;
    function interval () {
        intervalTimes++;
        if (intervalTimes >= 10) {
            clearInterval(interv);
        }
    }
    var interv = setInterval(interval, 10);

    5.2 使用function而不是string
    說明:如果把字符串作為setTimeout和setInterval的參數,瀏覽器會先用這個字符串構建一個function。

    服用前:
    var num = 0;
    setTimeout('num++', 10);   

    服用后:
    var num = 0;
    function addNum () {
        num++;
    }
    setTimeout(addNum, 10);


    6. 其他

    6.1 盡量不使用動態語法元素
    說明:eval、Function、execScript等語句會再次使用javascript解析引擎進行解析,需要消耗大量的執行時間。

    6.2 重復使用的調用結果,事先保存到局部變量
    說明:避免多次取值的調用開銷。

    服用前:
    var h1 = element1.clientHeight + num1;
    var h2 = element1.clientHeight + num2;

    服用后:
    var eleHeight = element1.clientHeight;
    var h1 = eleHeight + num1;
    var h2 = eleHeight + num2;

    6.3 使用直接量
    說明:
    var a = new Array(param,param,...) -> var a = []
    var foo = new Object() -> var foo = {}
    var reg = new RegExp() -> var reg = /.../

    6.4 避免使用with
    說明: with雖然可以縮短代碼量,但是會在運行時構造一個新的scope。
    OperaDev上還有這樣的解釋,使用with語句會使得解釋器無法在語法解析階段對代碼進行優化。對此說法,無法驗證。

    服用前:
    with (a.b.c.d) {
    property1 = 1;
    property2 = 2;
    }


    服用后:
    var obj = a.b.c.d;
    obj.property1 = 1;
    obj.property2 = 2;


    6.5 巧用||和&&布爾運算符

    服用前:
    function eventHandler (e) {
    if(!e) e = window.event;
    }


    服用后:
    function eventHandler (e) {
    e = e || window.event;
    }


    服用前:
    if (myobj) {
    doSomething(myobj);
    }


    服用后:
    myobj && doSomething(myobj);


    6.6 類型轉換
    說明:
    1).    數字轉換成字符串,應用"" + 1,性能上:("" +) > String() > .toString() > new String();
    2).    浮點數轉換成整型,不使用parseInt(), parseInt()是用于將字符串轉換成數字,而不是浮點數和整型之間的轉換,建議使用Math.floor()或者Math.round()
    3).    對于自定義的對象,推薦顯式調用toString()。內部操作在嘗試所有可能性之后,會嘗試對象的toString()方法嘗試能否轉化為String。


    二.內存管理

    2.1 循環引用
    說明:如果循環引用中包含DOM對象或者ActiveX對象,那么就會發生內存泄露。內存泄露的后果是在瀏覽器關閉前,即使是刷新頁面,這部分內存不會被瀏覽器釋放。

    簡單的循環引用:
    var el = document.getElementById('MyElement');
    var func = function () {…}
    el.func = func;
    func.element = el;


    但是通常不會出現這種情況。通常循環引用發生在為dom元素添加閉包作為expendo的時候。

    如:
    function init() {
        var el = document.getElementById('MyElement');
    el.onclick = function () {……}
    }
    init();


    init在執行的時候,當前上下文我們叫做context。這個時候,context引用了el,el引用了function,function引用了context。這時候形成了一個循環引用。

    下面2種方法可以解決循環引用:

    1)    置空dom對象

    服用前:
    function init() {
    var el = document.getElementById('MyElement');
    el.onclick = function () {……}
    }
    init();


    服用后:
    function init() {
    var el = document.getElementById('MyElement');
    el.onclick = function () {……}
    el = null;
    }
    init();


    將el置空,context中不包含對dom對象的引用,從而打斷循環應用。
    如果我們需要將dom對象返回,可以用如下方法:

    服用前:
    function init() {
        var el = document.getElementById('MyElement');
        el.onclick = function () {……}
        return el;
    }
    init();


    服用后:
    function init() {
    var el = document.getElementById('MyElement');
    el.onclick = function () {……}
    try{
    return el;
    } finally {
        el = null;
    }
    }
    init();

    2)    構造新的context
    服用前:
    function init() {
        var el = document.getElementById('MyElement');
        el.onclick = function () {……}
    }
    init();


    服用后:
    function elClickHandler() {……}
    function init() {
        var el = document.getElementById('MyElement');
        el.onclick = elClickHandler;
    }
    init();

    把function抽到新的context中,這樣,function的context就不包含對el的引用,從而打斷循環引用。

    2.2 通過javascript創建的dom對象,必須append到頁面中
    說明:IE下,腳本創建的dom對象,如果沒有append到頁面中,刷新頁面,這部分內存是不會回收的!

    示例代碼:

        function create () {
            var gc = document.getElementById('GC');
            for (var i = 0; i < 5000 ; i++)
            {
                var el = document.createElement('div');
                el.innerHTML = "test";

                //下面這句可以注釋掉,看看瀏覽器在任務管理器中,點擊按鈕然后刷新后的內存變化
                gc.appendChild(el);
            }
        }


    2.3 釋放dom元素占用的內存
    說明:
    將dom元素的innerHTML設置為空字符串,可以釋放其子元素占用的內存。
    在rich應用中,用戶也許會在一個頁面上停留很長時間,可以使用該方法釋放積累得越來越多的dom元素使用的內存。

    2.4 釋放javascript對象
    說明:在rich應用中,隨著實例化對象數量的增加,內存消耗會越來越大。所以應當及時釋放對對象的引用,讓GC能夠回收這些內存控件。
    對象:obj = null
    對象屬性:delete obj.myproperty
    數組item:使用數組的splice方法釋放數組中不用的item

    2.5 避免string的隱式裝箱
    說明:對string的方法調用,比如'xxx'.length,瀏覽器會進行一個隱式的裝箱操作,將字符串先轉換成一個String對象。推薦對聲明有可能使用String實例方法的字符串時,采用如下寫法:
    var myString = new String('Hello World');

    posted on 2012-07-25 06:44 zx_bing 閱讀(139) 評論(0)  編輯  收藏 所屬分類: js

    主站蜘蛛池模板: 亚洲色欲啪啪久久WWW综合网| 337p日本欧洲亚洲大胆色噜噜| 亚洲Aⅴ在线无码播放毛片一线天 亚洲avav天堂av在线网毛片 | 国产免费网站看v片在线| 亚洲一区二区三区乱码A| 无码免费又爽又高潮喷水的视频| 四虎永久在线免费观看| 国产亚洲精品仙踪林在线播放| 国产精品深夜福利免费观看 | 亚洲精品天堂成人片?V在线播放| 男人j进女人p免费视频| 亚洲综合另类小说色区色噜噜| 国产精品午夜免费观看网站| 亚洲国产精品无码成人片久久| 黄网站免费在线观看| 亚洲精品不卡视频| 免费A级毛片无码免费视| 亚洲精品无AMM毛片| 亚洲国产成人久久一区WWW| 最近免费字幕中文大全| 久久亚洲AV成人无码电影| 67194熟妇在线永久免费观看| 日韩亚洲人成在线| 亚洲AV日韩精品一区二区三区| 国产成人高清精品免费观看| 亚洲av最新在线网址| 2021国产精品成人免费视频| 最新亚洲人成无码网站| 久久综合图区亚洲综合图区| 91香蕉视频免费| 人碰人碰人成人免费视频| 久久久久亚洲av无码专区蜜芽| 丁香花免费完整高清观看| 一区二区三区免费在线视频 | 亚洲国产成人AV在线播放| 亚洲七七久久精品中文国产| 久久午夜羞羞影院免费观看 | 亚洲乱码日产精品BD在线观看| 国产精品冒白浆免费视频| 中文在线免费视频| 2020国产精品亚洲综合网|