摘要:可維護(hù)解耦采用引入文件的方式取代在頁面寫代碼避免在中創(chuàng)建大量當(dāng)用于插入數(shù)據(jù)時,盡量不要直接插入標(biāo)記。簡化循環(huán)體循環(huán)體是執(zhí)行最多的,所以要確保其被最大限地優(yōu)化,確保沒有某些可以被很容易移除循環(huán)的密集計算。
可維護(hù) 解耦HTML/JavaScript
1、采用引入js文件的方式取代在html頁面寫js代碼
2、避免在js中創(chuàng)建大量html
(1)當(dāng)js用于插入數(shù)據(jù)時,盡量不要直接插入標(biāo)記。一般可以在頁面中直接包含并隱藏標(biāo)記,然后等到整個頁面渲染好之后,就可以用js顯示該標(biāo)記,而非生成它
(2)也可以通過Ajax請求獲得更多要顯示的html,這個方法可以讓同樣的渲染層(PHP、JSP、Ruby等等)來輸出標(biāo)記,而不是直接嵌在js中
盡量不要在js中更改樣式,而是采用動態(tài)更改樣式類,從而做到對于樣式的問題應(yīng)只查看CSS文件來解決,例:
element.style.color = "red"; element.style.backgroundColor = "blue"; 更改后: element.className = "edit";解耦應(yīng)用邏輯/事件處理程序
每個web應(yīng)用一般都有相當(dāng)多的事件處理程序,監(jiān)聽這無數(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"; } } }
這個事件處理程序處理包含了應(yīng)用邏輯,還進(jìn)行了事件處理,這種方式的問題有其雙重性
(1)、處理通過事件之外就沒有辦法執(zhí)行應(yīng)用邏輯
(2)、調(diào)試?yán)щy,如果沒有發(fā)生預(yù)想的結(jié)果,并不知道是事件沒被調(diào)用還是應(yīng)用邏輯失敗
(3)、如果后續(xù)的事件需要執(zhí)行相同的應(yīng)用邏輯,那么就必須復(fù)制功能代碼或?qū)⒋a抽到一個多帶帶的函數(shù)中所以就好進(jìn)行兩者的解耦,即一個事件處理程序應(yīng)該從事件對象中提取相關(guān)信息,并將這些信息傳送到處理應(yīng)用邏輯的某個方法中,前面例子重寫如下:
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()中沒有任何東西會依賴于任何事件處理程序邏輯,他只接收一個值,并根據(jù)該值進(jìn)行其他處理
好處:如果事件最初只有鼠標(biāo)事件觸發(fā),那么現(xiàn)在只需少量修改就可以實現(xiàn)按鍵觸發(fā)
最多創(chuàng)建一個全局變量,讓其他對象和函數(shù)存在其中,如:
//兩個全局變量——避免!! let name= "bad"; function sayName() { alert(name); } //一個全局變量——推薦 let good = { name: "nice", sayName: function () { alert(this.name); } }
多人協(xié)作開發(fā)可以使用命名空間
//創(chuàng)建全局對象 let wrox = {}; //為Tony創(chuàng)建命名空間 wrox.Tony = {}; //為Tony(可以以人名劃分)創(chuàng)建方法 wrox.Tony.sayName = function () { ... };
上述例子,wrox是全局變量,其他命名空間在此之上創(chuàng)建,只要所有人都按這樣寫,那么就不用當(dāng)心不同開發(fā)者創(chuàng)建相同的方法等,因為它存在于不同的命名空間
避免與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)化
因為訪問全局變量要比訪問局部變量慢,因為要遍歷作用域鏈,所以減少花費(fèi)在作用域鏈上的時間,就可以增加腳本的整體新能
避免全局查找//bad function updateUI () { let imgs = document.getElementsByTagName("img"); for(let i=0, len=imgs.length; i使用事件代理上面將document對象保存在doc變量中,然后替換原來的document,與原來相比,只需進(jìn)行一次全局查找,速度肯定更快
循環(huán)優(yōu)化循環(huán)優(yōu)化基本步驟如下:
1、減值迭代——大多數(shù)循環(huán)使用一個從0開始、增加到某個特定值的迭代器。在很多情況下,從最大值開始,在循環(huán)中的迭代器更加高效。
2、簡化終止條件——由于每次循環(huán)過程都會計算終止條件,所以必須保證它盡可能快。也就是說避免屬性查找或者其他O(n)的操作。
3、簡化循環(huán)體——循環(huán)體是執(zhí)行最多的,所以要確保其被最大限地優(yōu)化,確保沒有某些可以被很容易移除循環(huán)的密集計算。
4、使用后側(cè)試循環(huán)——最常用的for循環(huán)和while循環(huán)都是前測試循環(huán)。而入do—while這種后側(cè)試循環(huán),可以避免最初終止條件的計算//基本for循環(huán) for(let i=0;i最小語句數(shù)=0; i--){ process(values[i]); } //再進(jìn)行改造成后測試循環(huán),此處主要的優(yōu)化是將終止條件和自減操作符組合成了單個語句 let i = values.length - 1; if(i> -1){ do{ process(valeus[i]); }while(--i>=0) } 1、多個聲明變量
//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ù)組和對象字面量
//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)場更新
//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個項目,每添加個項目時,都有2個現(xiàn)場更新:一個添加元素,另一個給他添加文本節(jié)點(diǎn),這樣添加10個項目,這個操作總共要完成20個現(xiàn)場更新。
解決方法:
1、將列表從頁面上移除,最后進(jìn)行更新,最后在將列表插回到同樣的位置,看似很美好,但這樣做會導(dǎo)致在每次更新的時候它會不必要的閃爍
2、使用文檔碎片來構(gòu)建DOM結(jié)構(gòu),接著將其添加到list元素中,這個方式避免了閃爍,如下://good,只有一次現(xiàn)場更新 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
有兩種方式在頁面上創(chuàng)建DOM節(jié)點(diǎn):使用諸如createElement()和appendChild()之類的DOM方法,以及使用innerHTML。對于小的DOM而言,兩者效率差不多,對于大的DOM改動,使用innerHTML要快得多。
原因:當(dāng)把innerHTML設(shè)置為某個值時,后臺會創(chuàng)建一個HTML解析器,然后使用內(nèi)部的DOM調(diào)用來創(chuàng)建DOM結(jié)構(gòu),而非基于js的DOM調(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)建好一個字符串然后一次性調(diào)用innerHTML
頁面上的事件處理程序的數(shù)量和頁面的響應(yīng)用戶交互的速度之間是負(fù)相關(guān)的
任何冒泡的事件都不僅僅可以在事件的目標(biāo)上進(jìn)行處理,目標(biāo)的任何祖先節(jié)點(diǎn)上也能處理,如果可能,在文檔級別附加事件處理程序,這樣就可以處理整個頁面的事件
任何時候要訪問HTMLCollection,不管是一個屬性還是一個方法,都是在文檔上進(jìn)行的一個查詢,這個查詢開銷很昂貴,爾等消費(fèi)不起
let images = document.getElementsByTagName("img"); imags, i, len; for(i=0; len=images.length; itip:發(fā)生以下情況會返回HTMLCollection對象:
展開循環(huán)(Duff)
(1)、進(jìn)行了對getElementsByTagName()的調(diào)用;
(2)、獲取了元素的childNodes屬性;
(3)、獲取了元素的attribute屬性;
(4)、訪問了特殊的集合,如document.forms、document.images等當(dāng)循環(huán)的次數(shù)是確定的,消除循環(huán)并使用多次函數(shù)調(diào)用往往更快,
//low for(let i=0;i<3;i++){ process(values[i]); } //fast,消除建立循環(huán)和處理終止條件的額外開銷 process(values[0]); process(values[1]); process(values[2]);如果迭代次數(shù)事項不能確定,可以使用Duff裝置的技術(shù)
Duff:通過計算迭代的次數(shù)是否為8的倍數(shù)將一個循環(huán)展開為一系列語句let iterations = Math.ceil(values.length / 8); //向上取整確保結(jié)果是整數(shù) let startAt = values.length % 8; //獲取無法通過上面進(jìn)行處理的項,如果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(),展開循環(huán)可以提升大數(shù)據(jù)集的處理速度。
將do-while循環(huán)分成2個多帶帶的循環(huán)可以讓Duff更快let iterations = Math.ceil(values.length / 8); //向上取整確保結(jié)果是整數(shù) let startAt = values.length % 8; //獲取無法通過上面進(jìn)行處理的項,如果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);上面代碼讓剩余的計算部分不會在實際循環(huán)中處理,而是在一個初始化循環(huán)中進(jìn)行除以8的操作,當(dāng)處理掉了額外的元素,繼續(xù)執(zhí)行每次調(diào)用8次process()的主循環(huán),這個方法幾乎比原始的Duff裝置快40%
其他性能優(yōu)化注意事項
tip:以上只適用于處理大數(shù)據(jù)集下面并非主要影響性能的主要問題,應(yīng)用得當(dāng),會有相當(dāng)大的提升
1、原生方法較快——只要有可能,使用原生方法而不是自己用js重寫一個,因為原生方法是用注入C/C++之類的編譯型語言寫出來的,所以要比js快得多,比如要用Math對象的數(shù)學(xué)運(yùn)算
2、Swithc語句較快——如果有一系列復(fù)雜的if-else語句,可以轉(zhuǎn)換成單個switch語句則可以得到更快的代碼,還可以通過將case語句按照最可以能的到最不可能的順序進(jìn)行組織,來進(jìn)一步優(yōu)化switch語句。
3、位運(yùn)算符較快——當(dāng)進(jìn)行數(shù)學(xué)運(yùn)算時,位運(yùn)算符操作要比任何布爾運(yùn)算或者算數(shù)運(yùn)算快,諸如取模,邏輯與和邏輯或都可以考慮用位運(yùn)算替換以上內(nèi)容參考自《JavaScript 高級程序設(shè)計(第三版)》
終于寫完了(~ ̄▽ ̄)~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/99157.html
摘要:前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開發(fā)教程工程實踐深度閱讀開源項目巔峰人生等欄目。對該漏洞的綜合評級為高危。目前,相關(guān)利用方式已經(jīng)在互聯(lián)網(wǎng)上公開,近期出現(xiàn)攻擊嘗試爆發(fā)的可能。 前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn);分為新聞熱點(diǎn)、開發(fā)教程、工程實踐、深度閱讀、開源項目、巔峰人生等欄目。歡...
摘要:谷歌,,,雅虎和最近因世界杯獲得龐大觀眾數(shù)量的都在使用。因此,數(shù)據(jù)庫服務(wù)器的能力是毋庸置疑的。微軟的服務(wù)器,服務(wù)器以及未來的更新價格昂貴。更依賴于微軟數(shù)量有限的開發(fā)者做出的改進(jìn)和更新。 【編者按】本文主要針對開源 PHP 和非開源的 ASP.NET 在性能、成本、可擴(kuò)展性,技術(shù)支持和復(fù)雜性等方面進(jìn)行比較。 在網(wǎng)上論壇,總是有成百上千的文章和帖子在討論 PHP 和 ASP.NET,究竟誰...
摘要:相反,我們將專注于將添加到用編寫的簡單應(yīng)用程序中。使用創(chuàng)建應(yīng)用程序。示例應(yīng)用程序有兩個組件應(yīng)用程序和。除在全球率先支持外,現(xiàn)已全面應(yīng)用于等主流框架中。 showImg(https://segmentfault.com/img/bVbcvaQ?w=500&h=278); 概述 在本文中,我們將展示如何將WijmoJS與NPM和Webpack一起使用來創(chuàng)建最流行的基于JavaScript應(yīng)...
摘要:前端每周清單第期與模式變遷與優(yōu)化界面生成作者王下邀月熊編輯徐川前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開發(fā)教程工程實踐深度閱讀開源項目巔峰人生等欄目。 showImg(https://segmentfault.com/img/remote/1460000013279448); 前端每周清單第 51 期: React Context A...
閱讀 2305·2021-09-28 09:45
閱讀 3596·2021-09-24 09:48
閱讀 2256·2021-09-22 15:49
閱讀 3093·2021-09-08 16:10
閱讀 1586·2019-08-30 15:54
閱讀 2317·2019-08-30 15:53
閱讀 3012·2019-08-29 18:42
閱讀 2865·2019-08-29 16:19