成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

js編寫(xiě)的可維護(hù)與性能優(yōu)化

YFan / 1040人閱讀

摘要:可維護(hù)解耦采用引入文件的方式取代在頁(yè)面寫(xiě)代碼避免在中創(chuàng)建大量當(dāng)用于插入數(shù)據(jù)時(shí),盡量不要直接插入標(biāo)記。簡(jiǎn)化循環(huán)體循環(huán)體是執(zhí)行最多的,所以要確保其被最大限地優(yōu)化,確保沒(méi)有某些可以被很容易移除循環(huán)的密集計(jì)算。

可維護(hù) 解耦HTML/JavaScript

1、采用引入js文件的方式取代在html頁(yè)面寫(xiě)js代碼
2、避免在js中創(chuàng)建大量html
(1)當(dāng)js用于插入數(shù)據(jù)時(shí),盡量不要直接插入標(biāo)記。一般可以在頁(yè)面中直接包含并隱藏標(biāo)記,然后等到整個(gè)頁(yè)面渲染好之后,就可以用js顯示該標(biāo)記,而非生成它
(2)也可以通過(guò)Ajax請(qǐng)求獲得更多要顯示的html,這個(gè)方法可以讓同樣的渲染層(PHP、JSP、Ruby等等)來(lái)輸出標(biāo)記,而不是直接嵌在js

解耦CSS/JavaScript

盡量不要在js中更改樣式,而是采用動(dòng)態(tài)更改樣式類,從而做到對(duì)于樣式的問(wèn)題應(yīng)只查看CSS文件來(lái)解決,例:

element.style.color = "red";
element.style.backgroundColor = "blue";

更改后:
element.className = "edit";
解耦應(yīng)用邏輯/事件處理程序

每個(gè)web應(yīng)用一般都有相當(dāng)多的事件處理程序,監(jiān)聽(tīng)這無(wú)數(shù)不同的事件,然而,很少有能仔細(xì)得將應(yīng)用邏輯從事件處理程序中分離的,如下:

function handleKeyPress (event) {
    if(event.keyCode == 1){
        let target = event;
        let value = 5 * parseInt(target.value);
        if(value > 10){
            document.getElementById("tip-msg").style.display = "block";
        }
    }
}

這個(gè)事件處理程序處理包含了應(yīng)用邏輯,還進(jìn)行了事件處理,這種方式的問(wèn)題有其雙重性
(1)、處理通過(guò)事件之外就沒(méi)有辦法執(zhí)行應(yīng)用邏輯
(2)、調(diào)試?yán)щy,如果沒(méi)有發(fā)生預(yù)想的結(jié)果,并不知道是事件沒(méi)被調(diào)用還是應(yīng)用邏輯失敗
(3)、如果后續(xù)的事件需要執(zhí)行相同的應(yīng)用邏輯,那么就必須復(fù)制功能代碼或?qū)⒋a抽到一個(gè)多帶帶的函數(shù)中所以就好進(jìn)行兩者的解耦,即一個(gè)事件處理程序應(yīng)該從事件對(duì)象中提取相關(guān)信息,并將這些信息傳送到處理應(yīng)用邏輯的某個(gè)方法中,前面例子重寫(xiě)如下:

function validateValue (value) {
    value = 5 * parseInt(value);
    if(value > 10){
        document.getElementById("tip-msg").style.display = "block";
    }
}

function handleKeyPress (event) {
    if(event.keyCode == 13){
        let target = event;
        validateValue(target.value);
    }
}

從而使validateValue()中沒(méi)有任何東西會(huì)依賴于任何事件處理程序邏輯,他只接收一個(gè)值,并根據(jù)該值進(jìn)行其他處理
好處:如果事件最初只有鼠標(biāo)事件觸發(fā),那么現(xiàn)在只需少量修改就可以實(shí)現(xiàn)按鍵觸發(fā)

避免全局變量

最多創(chuàng)建一個(gè)全局變量,讓其他對(duì)象和函數(shù)存在其中,如:

//兩個(gè)全局變量——避免??!
let name= "bad";
function sayName() {
    alert(name);
}    

//一個(gè)全局變量——推薦
let good = {
    name: "nice",
    sayName: function () {
        alert(this.name);
    }
}

多人協(xié)作開(kāi)發(fā)可以使用命名空間

//創(chuàng)建全局對(duì)象
let wrox = {};

//為T(mén)ony創(chuàng)建命名空間
wrox.Tony = {};

//為T(mén)ony(可以以人名劃分)創(chuàng)建方法
wrox.Tony.sayName = function () {
    ...
};

上述例子,wrox是全局變量,其他命名空間在此之上創(chuàng)建,只要所有人都按這樣寫(xiě),那么就不用當(dāng)心不同開(kāi)發(fā)者創(chuàng)建相同的方法等,因?yàn)樗嬖谟诓煌拿臻g

避免與null進(jìn)行比較

應(yīng)該讓條件與預(yù)想的類型進(jìn)行比較而不是與null

//bad
function sortArray(values) {
    if(values != null){
        ...
    }
}
//good
function sortArray(values) {
    if(values instanceof Array){
        ...
    }    
}
抽離常量
const constants = {
    INVALID_VALUE_MSG:"Invalid value!",
    INVALID_VALUE_URL:"/errors/invalid.php"
}
性能優(yōu)化

因?yàn)樵L問(wèn)全局變量要比訪問(wèn)局部變量慢,因?yàn)橐闅v作用域鏈,所以減少花費(fèi)在作用域鏈上的時(shí)間,就可以增加腳本的整體新能

避免全局查找
//bad
function updateUI () {
    let imgs = document.getElementsByTagName("img");
    for(let i=0, len=imgs.length; i

上面將document對(duì)象保存在doc變量中,然后替換原來(lái)的document,與原來(lái)相比,只需進(jìn)行一次全局查找,速度肯定更快

循環(huán)優(yōu)化

循環(huán)優(yōu)化基本步驟如下:
1、減值迭代——大多數(shù)循環(huán)使用一個(gè)從0開(kāi)始、增加到某個(gè)特定值的迭代器。在很多情況下,從最大值開(kāi)始,在循環(huán)中的迭代器更加高效。
2、簡(jiǎn)化終止條件——由于每次循環(huán)過(guò)程都會(huì)計(jì)算終止條件,所以必須保證它盡可能快。也就是說(shuō)避免屬性查找或者其他O(n)的操作。
3、簡(jiǎn)化循環(huán)體——循環(huán)體是執(zhí)行最多的,所以要確保其被最大限地優(yōu)化,確保沒(méi)有某些可以被很容易移除循環(huán)的密集計(jì)算。
4、使用后側(cè)試循環(huán)——最常用的for循環(huán)和while循環(huán)都是前測(cè)試循環(huán)。而入do—while這種后側(cè)試循環(huán),可以避免最初終止條件的計(jì)算

//基本for循環(huán)
for(let i=0;i=0; i--){
    process(values[i]);
}
//再進(jìn)行改造成后測(cè)試循環(huán),此處主要的優(yōu)化是將終止條件和自減操作符組合成了單個(gè)語(yǔ)句
let i = values.length - 1;
if(i> -1){
    do{
        process(valeus[i]);
    }while(--i>=0)
}
最小語(yǔ)句數(shù)

1、多個(gè)聲明變量

//bad
let count = 5;
let color = "blue";
let values = [1,2,3];
let now = new Date();
//good
let count = 5,
    color = "blue",
    values = [1,2,3],
    now = new Date();

2、插入迭代值

//bad
let name = values[i];
i++;
//good
let name = values[i++];

3、使用數(shù)組和對(duì)象字面量

//bad
let values = new Array();
values[0] = 123;
values[1] = 456;
values[2] = 789;
//bad
let person = new Object();
person.name = "Tony";
person.age = 18;
person.sayName = function () {
    alert(this.name);
}

//good
let values = [123,456,789];
let person = {
    name: "Tony",
    age: 18,
    sayName: function () {
        alert(this.name);
    }
}
優(yōu)化DOM交互

1、最小現(xiàn)場(chǎng)更新

//bad
let list = document.getElementById("myList"),
    item,
    i;
for(i=0; i<10; i++){
    item = document.createElement("li");
    list = appendChilde(item);
    item.appendChild(document.createTextNode("Item" + i);
}

上述代碼為列表添加了10個(gè)項(xiàng)目,每添加個(gè)項(xiàng)目時(shí),都有2個(gè)現(xiàn)場(chǎng)更新:一個(gè)添加

  • 元素,另一個(gè)給他添加文本節(jié)點(diǎn),這樣添加10個(gè)項(xiàng)目,這個(gè)操作總共要完成20個(gè)現(xiàn)場(chǎng)更新。
    解決方法:
    1、將列表從頁(yè)面上移除,最后進(jìn)行更新,最后在將列表插回到同樣的位置,看似很美好,但這樣做會(huì)導(dǎo)致在每次更新的時(shí)候它會(huì)不必要的閃爍
    2、使用文檔碎片來(lái)構(gòu)建DOM結(jié)構(gòu),接著將其添加到list元素中,這個(gè)方式避免了閃爍,如下:

    //good,只有一次現(xiàn)場(chǎng)更新
    let list = document.getElementById("myList");
        framgent = document.createDocumentFragment(),
        itme,
        i;
    for(i=0; i<10; i++){
        item = document.createElement("li");
        fragment.appendChild(item);
        item.appendChild(document.createTextNode("Item" + i));
    }
    list.appendChild(fragment);

    2、使用innerHTML
    有兩種方式在頁(yè)面上創(chuàng)建DOM節(jié)點(diǎn):使用諸如createElement()appendChild()之類的DOM方法,以及使用innerHTML。對(duì)于小的DOM而言,兩者效率差不多,對(duì)于大的DOM改動(dòng),使用innerHTML要快得多。
    原因:當(dāng)把innerHTML設(shè)置為某個(gè)值時(shí),后臺(tái)會(huì)創(chuàng)建一個(gè)HTML解析器,然后使用內(nèi)部的DOM調(diào)用來(lái)創(chuàng)建DOM結(jié)構(gòu),而非基于jsDOM調(diào)用,由于內(nèi)部方法是編譯好的而非解釋執(zhí)行的,所以執(zhí)行快得多,所以上面例子還可以優(yōu)化

    let list = document.getElementById("myList"),
        html = "",
        i;
    for(i=0; i<10; i++){
        html += `
  • Item${i}
  • `; } list.innerHTML = html; //tip同樣要避免多次調(diào)用innerHTML,即要做到構(gòu)建好一個(gè)字符串然后一次性調(diào)用innerHTML
    使用事件代理

    頁(yè)面上的事件處理程序的數(shù)量和頁(yè)面的響應(yīng)用戶交互的速度之間是負(fù)相關(guān)的
    任何冒泡的事件都不僅僅可以在事件的目標(biāo)上進(jìn)行處理,目標(biāo)的任何祖先節(jié)點(diǎn)上也能處理,如果可能,在文檔級(jí)別附加事件處理程序,這樣就可以處理整個(gè)頁(yè)面的事件

    注意HTMLCollection

    任何時(shí)候要訪問(wèn)HTMLCollection,不管是一個(gè)屬性還是一個(gè)方法,都是在文檔上進(jìn)行的一個(gè)查詢,這個(gè)查詢開(kāi)銷很昂貴,爾等消費(fèi)不起

    let images = document.getElementsByTagName("img");
        imags,
        i,
        len;
    for(i=0; len=images.length; i
    

    tip:發(fā)生以下情況會(huì)返回HTMLCollection對(duì)象:
    (1)、進(jìn)行了對(duì)getElementsByTagName()的調(diào)用;
    (2)、獲取了元素的childNodes屬性;
    (3)、獲取了元素的attribute屬性;
    (4)、訪問(wèn)了特殊的集合,如document.forms、document.images

    展開(kāi)循環(huán)(Duff)

    當(dāng)循環(huán)的次數(shù)是確定的,消除循環(huán)并使用多次函數(shù)調(diào)用往往更快,

    //low
    for(let i=0;i<3;i++){
        process(values[i]);
    }
    //fast,消除建立循環(huán)和處理終止條件的額外開(kāi)銷
    process(values[0]);
    process(values[1]);
    process(values[2]);

    如果迭代次數(shù)事項(xiàng)不能確定,可以使用Duff裝置的技術(shù)
    Duff:通過(guò)計(jì)算迭代的次數(shù)是否為8的倍數(shù)將一個(gè)循環(huán)展開(kāi)為一系列語(yǔ)句

    let iterations = Math.ceil(values.length / 8); //向上取整確保結(jié)果是整數(shù)
    let startAt = values.length % 8; //獲取無(wú)法通過(guò)上面進(jìn)行處理的項(xiàng),如果values.length為10,那么startAt為2
    let i = 0;
    
    do {
        switch(startAt) {
            case 0: process(values[i++]);
            case 7: process(values[i++]);
            case 6: process(values[i++]);
            case 5: process(values[i++]);
            case 4: process(values[i++]);
            case 3: process(values[i++]);
            case 2: process(values[i++]);
            case 1: process(values[i++]);
        }
        startAt = 0;
    } while (--iterations > 0);

    上面運(yùn)行的結(jié)果是先運(yùn)行startAt次的process(),然后startAt設(shè)置為0,后面循環(huán)都執(zhí)行8次process(),展開(kāi)循環(huán)可以提升大數(shù)據(jù)集的處理速度。
    do-while循環(huán)分成2個(gè)多帶帶的循環(huán)可以讓Duff更快

    let iterations = Math.ceil(values.length / 8); //向上取整確保結(jié)果是整數(shù)
    let startAt = values.length % 8; //獲取無(wú)法通過(guò)上面進(jìn)行處理的項(xiàng),如果values.length為10,那么startAt為2
    let i = 0;
    
    if(leftover > 0){           
        do{
            process(values[i++]);
        } while (--leftover > 0);
    }
    do {
        process(values[i++]);
        process(values[i++]);
        process(values[i++]);
        process(values[i++]);
        process(values[i++]);
        process(values[i++]);
        process(values[i++]);
        process(values[i++]);
    } while (--iterations > 0);

    上面代碼讓剩余的計(jì)算部分不會(huì)在實(shí)際循環(huán)中處理,而是在一個(gè)初始化循環(huán)中進(jìn)行除以8的操作,當(dāng)處理掉了額外的元素,繼續(xù)執(zhí)行每次調(diào)用8次process()的主循環(huán),這個(gè)方法幾乎比原始的Duff裝置快40%
    tip:以上只適用于處理大數(shù)據(jù)集

    其他性能優(yōu)化注意事項(xiàng)

    下面并非主要影響性能的主要問(wèn)題,應(yīng)用得當(dāng),會(huì)有相當(dāng)大的提升
    1、原生方法較快——只要有可能,使用原生方法而不是自己用js重寫(xiě)一個(gè),因?yàn)樵椒ㄊ怯米⑷?b>C/C++之類的編譯型語(yǔ)言寫(xiě)出來(lái)的,所以要比js快得多,比如要用Math對(duì)象的數(shù)學(xué)運(yùn)算
    2、Swithc語(yǔ)句較快——如果有一系列復(fù)雜的if-else語(yǔ)句,可以轉(zhuǎn)換成單個(gè)switch語(yǔ)句則可以得到更快的代碼,還可以通過(guò)將case語(yǔ)句按照最可以能的到最不可能的順序進(jìn)行組織,來(lái)進(jìn)一步優(yōu)化switch語(yǔ)句。
    3、位運(yùn)算符較快——當(dāng)進(jìn)行數(shù)學(xué)運(yùn)算時(shí),位運(yùn)算符操作要比任何布爾運(yùn)算或者算數(shù)運(yùn)算快,諸如取模,邏輯與和邏輯或都可以考慮用位運(yùn)算替換

    以上內(nèi)容參考自《JavaScript 高級(jí)程序設(shè)計(jì)(第三版)》
    終于寫(xiě)完了(~ ̄▽ ̄)~

  • 文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

    轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/99157.html

    相關(guān)文章

    • 前端每周清單半年盤(pán)點(diǎn)之 Node.js

      摘要:前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開(kāi)發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開(kāi)發(fā)教程工程實(shí)踐深度閱讀開(kāi)源項(xiàng)目巔峰人生等欄目。對(duì)該漏洞的綜合評(píng)級(jí)為高危。目前,相關(guān)利用方式已經(jīng)在互聯(lián)網(wǎng)上公開(kāi),近期出現(xiàn)攻擊嘗試爆發(fā)的可能。 前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開(kāi)發(fā)者了解一周前端熱點(diǎn);分為新聞熱點(diǎn)、開(kāi)發(fā)教程、工程實(shí)踐、深度閱讀、開(kāi)源項(xiàng)目、巔峰人生等欄目。歡...

      kid143 評(píng)論0 收藏0
    • 盤(pán)點(diǎn) PHP 和 ASP.NET 的10大對(duì)比!

      摘要:谷歌,,,雅虎和最近因世界杯獲得龐大觀眾數(shù)量的都在使用。因此,數(shù)據(jù)庫(kù)服務(wù)器的能力是毋庸置疑的。微軟的服務(wù)器,服務(wù)器以及未來(lái)的更新價(jià)格昂貴。更依賴于微軟數(shù)量有限的開(kāi)發(fā)者做出的改進(jìn)和更新。 【編者按】本文主要針對(duì)開(kāi)源 PHP 和非開(kāi)源的 ASP.NET 在性能、成本、可擴(kuò)展性,技術(shù)支持和復(fù)雜性等方面進(jìn)行比較。 在網(wǎng)上論壇,總是有成百上千的文章和帖子在討論 PHP 和 ASP.NET,究竟誰(shuí)...

      hosition 評(píng)論0 收藏0
    • 用WijmoJS玩轉(zhuǎn)您的Web應(yīng)用 —— Vue.js

      摘要:相反,我們將專注于將添加到用編寫(xiě)的簡(jiǎn)單應(yīng)用程序中。使用創(chuàng)建應(yīng)用程序。示例應(yīng)用程序有兩個(gè)組件應(yīng)用程序和。除在全球率先支持外,現(xiàn)已全面應(yīng)用于等主流框架中。 showImg(https://segmentfault.com/img/bVbcvaQ?w=500&h=278); 概述 在本文中,我們將展示如何將WijmoJS與NPM和Webpack一起使用來(lái)創(chuàng)建最流行的基于JavaScript應(yīng)...

      OnlyMyRailgun 評(píng)論0 收藏0
    • 前端每周清單第 51 期: React Context API 模式變遷, Webpack W

      摘要:前端每周清單第期與模式變遷與優(yōu)化界面生成作者王下邀月熊編輯徐川前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開(kāi)發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開(kāi)發(fā)教程工程實(shí)踐深度閱讀開(kāi)源項(xiàng)目巔峰人生等欄目。 showImg(https://segmentfault.com/img/remote/1460000013279448); 前端每周清單第 51 期: React Context A...

      Jiavan 評(píng)論0 收藏0

    發(fā)表評(píng)論

    0條評(píng)論

    閱讀需要支付1元查看
    <