注意作用域
避免全域查找
一個例子:
function updateUI(){ var imgs = document.getElementByTagName("img"); for(var i=0, len=imgs.length; i<len; i++){ imgs[i].title = document.title + " image " + i; } var msg = document.getElementById("msg"); msg.innnerHTML = "Update complete."; }
該函數可能看起來完全正常,但它包含了三個對於全域document物件的引用。如果在頁面上有多個圖片,那麼for迴圈中的document引用就會被執行多次甚至上百次,每次都會要進行作用域鏈查找。透過建立一個指向document物件的局部變量,就可以透過限制一次全域查找來改進這個函數的效能:
function updateUI(){ var doc = document; var imgs = doc.getElementByTagName("img"); for(var i=0, len=imgs.length; i<len; i++){ imgs[i].title = doc.title + " image " + i; } var msg = doc.getElementById("msg"); msg.innnerHTML = "Update complete."; }
這裡,首先將document物件存在本地的doc變數中;然後在餘下的程式碼中替換原來的document。與原來的版本相比,現在的函數只有一次全域查找,肯定更快。
選擇正確方法
1.避免不必要的屬性尋找
#取得常數值是非常有效率的過程
var value = 5; var sum = 10 + value; alert(sum);
程式碼進行了四次常數值查找:數字5,變數value,數字10和變數sum。
在JavaScript中存取陣列元素和簡單的變數尋找效率一樣。所以以下程式碼和前面的範例效率一樣:
var value = [5,10]; var sum = value[0] + value[1]; alert(sum);
物件上的任何屬性查找都比存取變數或陣列花費更長時間,因為必須在原型鏈中對擁有該名稱的屬性進行一次搜素。 屬性查找越多,執行時間越長。
var values = {first: 5, second: 10}; var sum = values.first + values.second; alert(sum);
這段程式碼使用兩次屬性尋找來計算sum的值。進行一兩次屬性查找並不會導致顯著的效能問題,但是進行數百次則肯定會減慢執行速度。
注意取得單一值的多重屬性查找。例如:
var query = window.location.href.substring(window.location.href.indexOf("?"));
在這段程式碼中,有6次屬性尋找:window.location.href.substring()有3次,window.location.href.indexOf()又有3次。 只要數一數程式碼中的點的數量,就可以確定查找的次數了。 這段程式碼因為兩次用到了window.location.href,同樣的查找進行了兩次,因此效率特別不好。
一旦多次使用到物件屬性,應該將其儲存在局部變數中。之前的程式碼可以如下重寫:
var url = window.locaiton.href; var query = url.substring(url.indexOf("?"));
這個版本的程式碼只有4次屬性查找,相對於原始版本節省了33%。
一般來講,只要能減少演算法的複雜度,就要盡量減少。盡可能多地使用局部變數將屬性查找替換為值查找,進一步獎,如果即可以用數字化的數組位置進行訪問,也可以使用命名屬性(諸如NodeList物件),那麼使用數字位置。
2.最佳化循環
一個循環的基本最佳化步驟如下所示。
(1)減損迭代-大多數迴圈使用一個從0開始、增加到某個特定值的迭代器。在很多情況下,從最大值開始,在循環中不斷減值的迭代器更有效率。
(2)簡化終止條件-由於每次迴圈過程都會計算終止條件,所以必須保證它盡可能快。也就是說避免屬性查找或其他操作。
(3)簡化迴圈體-迴圈是執行最多的,所以要確保其最大限度地最佳化,確保其他某些可以被輕易移除迴圈的密集計算。
(4使用後測試循環-最常用for迴圈和while迴圈都是前測迴圈。而如do-while這種後測迴圈,可以避免最初終止條件的計算,因此運行更快。 :
for(var i=0; i < value.length; i++){ process(values[i]); }
終止條件從value.length簡化成了0。將終止條件和自減運算子組合成了單一語句,循環部分已經最佳化完全了。多餘的一次迴圈而「前測」迴圈則可以避免。函數呼叫往往比較快。
如果循環中的迭代次數不能事先確定,那可以考慮使用一種叫做Duff裝置的技術。 Andrew B.King提出了一個更快的Duff裝置技術,將do-while循環分成2個單獨的循環。計算部分不會在實際迴圈中處理,而是在一個初始化迴圈中進行除以8的運算。 ##針對大數據集使用展開循環可以節省很多時間,但對於小數據集,額外的開銷則可能得不償失。來說不值得。4.避免双重解释
当JavaScript代码想解析KavaScript的时候就会存在双重解释惩罚。当使用eval()函数或者是Function构造函数以及使用setTimeout()传一个字符串参数时都会发生这种情况。
//某些代码求值——避免!! eval("alert('Hello world!')"); //创建新函数——避免!! var sayHi = new Function("alert('Hello world!')"); //设置超时——避免!! setTimeout("alert('Hello world!')", 500);
在以上这些例子中,都要解析包含了JavaScript代码的字符串。这个操作是不能在初始的解析过程中完成的,因为代码是包含在字符串中的,也就是说在JavaScript代码运行的同时必须新启动一个解析器来解析新的代码。实例化一个新的解析器有不容忽视的开销,所以这种代码要比直接解析慢得多。
//已修正 alert('Hello world!'); //创建新函数——已修正 var sayHi = function(){ alert('Hello world!'); }; //设置一个超时——已修正 setTimeout(function(){ alert('Hello world!'); }, 500);
如果要提高代码性能,尽可能避免出现需要按照JavaScript解析的字符串。
5.性能的其他注意事项
(1)原生方法较快
(2)Switch语句较快
(3)位运算符较快
最小化语句数
1.多个变量声明
//4个语句——很浪费 var count = 5; var color = "blue"; var values = [1,2,3]; var now = new Date(); //一个语句 var count = 5, color = "blue", values = [1,2,3], now = new Date();
2.插入迭代值
当使用迭代值的时候,尽可能合并语句。
var name = values[i]; i++;
前面这2句语句各只有一个目的:第一个从values数组中获取值,然后存储在name中;第二个给变量i增加1.这两句可以通过迭代值插入第一个语句组合成一个语句。
var name = values[i++];
3.使用数组和对象字面量
//用4个语句创建和初始化数组——浪费 var values = new Array(); values[0] = 123; values[1] = 456; values[2] = 789; //用4个语句创建和初始化对象——浪费 var person = new Object(); person.name = "Nicholas"; person.age = 29; person.sayName = function(){ alert(this.name); };
这段代码中,只创建和初始化了一个数组和一个对象。各用了4个语句:一个调用构造函数,其他3个分配数据。其实可以很容易地转换成使用字面量的形式。
//只有一条语句创建和初始化数组 var values = [13,456,789]; //只有一条语句创建和初始化对象 var person = { name : "Nicholas", age : 29, sayName : function(){ alert(this.name); } };
重写后的代码只包含两条语句,减少了75%的语句量,在包含成千上万行JavaScript的代码库中,这些优化的价值更大。
只要有可能,尽量使用数组和对象的字面量表达方式来消除不必要的语句。
优化DOM交互
1.最小化现场更新
一旦你需要访问的DOM部分是已经显示的页面的一部分,那么你就是在进行一个现场更新。现场更新进行得越多,代码完成执行所花的事件就越长。
var list = document.getElementById('myList'), item, i; for (var i = 0; i < 10; i++) { item = document.createElement("li"); list.appendChild(item); item.appendChild(document.createTextNode("Item" + i)); }
这段代码为列表添加了10个项目。添加每个项目时,都有2个现场更新:一个添加li元素,另一个给它添加文本节点。这样添加10个项目,这个操作总共要完成20个现场更新。
var list = document.getElementById('myList'), fragment = document.createDocumentFragment(), item, i; for (var i = 0; i < 10; i++) { item = document.createElement("li"); fragment.appendChild(item); item.appendChild(document.createTextNode("Item" + i)); } list.appendChild(fragment);
在这个例子中只有一次现场更新,它发生在所有项目都创建好之后。文档片段用作一个临时的占位符,放置新创建的项目。当给appendChild()传入文档片段时,只有片段中的子节点被添加到目标,片段本身不会被添加的。
一旦需要更新DOM,请考虑使用文档片段来构建DOM结构,然后再将其添加到现存的文档中。
2.使用innerHTML
有两种在页面上创建DOM节点的方法:使用诸如createElement()和appendChild()之类的DOM方法,以及使用innerHTML。对于小的DOM更改而言,两种方法效率都差不多。然而,对于大的DOM更改,使用innerHTML要比使用标准DOM方法创建同样的DOM结构快得多。
当把innerHTML设置为某个值时,后台会创建一个HTML解析器,然后使用内部的DOM调用来创建DOM结构,而非基于JavaScript的DOM调用。由于内部方法是编译好的而非解释执行的,所以执行快得多。
var list = document.getElementById("myList"); html = ""; i; for (i=0; i < 10; i++){ html += "<li>Item " + i +"</li>"; } list.innerHTML = html;
使用innerHTML的关键在于(和其他的DOM操作一样)最小化调用它的次数。
var list = document.getElementById("myList"); i; for (i=0; i < 10; i++){ list.innerHTML += "<li>Item " + i +"</li>"; //避免!!! }
这段代码的问题在于每次循环都要调用innerHTML,这是极其低效的。调用innerHTML实际上就是一次现场更新。构建好一个字符串然后一次性调用innerHTML要比调用innerHTML多次快得多。
3.使用事件代理(根据第13章的概念,我认为此处应为“事件委托”更为妥当)
4.注意HTMLCollection
任何时候要访问HTMLCollection,不管它是一个属性还是一个方法,都是在文档上进行一个查询,这个查询开销很昂贵。
var images = document.getElementsByTagName("img"), image, i,len; for (i=0, len=images.length; i < len; i++){ image = images[i]; //处理 }
将length和当前引用的images[i]存入变量,这样就可以最小化对他们的访问。发生以下情况时会返回HTMLCollection对象:
进行了对getElementsByTagName()的调用;
获取了元素的childNodes属性;
获取了元素的attributes属性;
访问了特殊的集合,如document.forms、document.images等。
以上就是详细介绍JavaScript最佳实践 –性能的内容,更多相关内容请关注PHP中文网(www.php.cn)!

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

Atom編輯器mac版下載
最受歡迎的的開源編輯器

Dreamweaver CS6
視覺化網頁開發工具

Dreamweaver Mac版
視覺化網頁開發工具