Javascript是一門非常靈活的語言,我們可以隨心所欲的書寫各種風格的程式碼,不同風格的程式碼也必然也會導致執行效率的差異,開發過程中零零散散地接觸到許多提升程式碼效能的方法,整理一下平時比較常見且容易規避的問題
Javascript本身執行效率
Javascript中的作用域鏈、閉包、原型繼承、eval等特性,在提供各種神奇功能的同時也帶來了各種效率問題,用之不慎就會導致執行效率低下。
1、全域導入
我們在編碼過程中多多少少會使用到一些全域變數(window,document,自訂全域變數等等),了解javascript作用域鏈的人都知道,在局部作用域中存取全域變數需要一層一層遍歷整個作用域鏈直至頂級作用域,而局部變數的存取效率則會更快更高,因此在局部作用域中高頻率使用一些全域物件時可以將其導入到局部作用域中,例如:
//1、作为参数传入模块 (function(window,$){ var xxx = window.xxx; $("#xxx1").xxx(); $("#xxx2").xxx(); })(window,jQuery); //2、暂存到局部变量 function(){ var doc = document; var global = window.global; }
2、eval以及類別eval問題
我們都知道eval可以將一段字串當做js程式碼來執行處理,據說使用eval執行的程式碼比不使用eval的程式碼慢100倍以上(具體效率我沒有測試,有興趣同學可以測試一下)
JavaScript 程式碼在執行前會進行類似「預先編譯」的操作:首先會建立一個目前執行環境下的活動對象,並將那些以var 申明的變數設為活動物件的屬性,但此時這些變數的賦值都是undefined,並將那些以function 定義的函數也加入為活動物件的屬性,而且它們的值正是函數的定義。但是,如果你使用了“eval”,則“eval”中的程式碼(實際上為字串)無法預先識別其上下文,無法事先解析和最佳化,即無法進行預編譯的操作。所以,其效能也會大幅降低
其實作在大家一般都很少會用eval了,這裡我想說的是兩個類別eval的場景(new Function{}
,setTimeout
,setInterver
)
setTimtout("alert(1)",1000); setInterver("alert(1)",1000); (new Function("alert(1)"))();
上述幾種型別程式碼執行效率都會比較低,因此建議直接傳入匿名方法、或方法的引用給setTimeout方法
3、閉包結束後釋放掉不再被引用的變數
var f = (function(){ var a = {name:"var3"}; var b = ["var1","var2"]; var c = document.getElementByTagName("li"); //****其它变量 //***一些运算 var res = function(){ alert(a.name); } return res; })()
上述程式碼中變數f的回傳值是由一個立即執行函數構成的閉包中傳回的方法res,該變數保留了對於這個閉包中所有變數(a,b,c等)的引用,因此這兩個變數會一直駐留在記憶體空間中,尤其是對於dom元素的引用對記憶體的消耗會很大,而我們在res中只使用到了a變數的值,因此,在閉包返回之前我們可以將其它變數釋放
var f = (function(){ var a = {name:"var3"}; var b = ["var1","var2"]; var c = document.getElementByTagName("li"); //****其它变量 //***一些运算 //闭包返回前释放掉不再使用的变量 b = c = null; var res = function(){ alert(a.name); } return res; })()
Js操作dom的效率
在web開發過程中,前端執行效率的瓶頸往往都是在dom操作上面,dom操作是一件很耗性能的事情,如何在dom操作過程中盡量節約效能呢?
1、減少reflow
什麼是reflow?
當 DOM 元素的屬性改變 (如 color) 時, 瀏覽器會通知 render 重新描繪對應的元素, 此程序稱為 repaint。
如果該次變更涉及元素佈局(如width), 瀏覽器則拋棄原有屬性, 重新計算並把結果傳遞給render 以重新描繪頁面元素, 此過程稱為reflow。
減少reflow的方法
先將元素從document中刪除,完成修改後再把元素放回原來的位置(當對某元素及其子元素進行大量reflow操作時,1,2兩種方法效果才會比較明顯)
#將元素的display設為”none”,完成修改後再把display修改為原來的值
修改多個樣式屬性時定義class類別代替多次修改style屬性(for certain同學推薦)
大量新增元素到頁面時使用documentFragment
#例如
for(var i=0;i<100:i++){ var child = docuemnt.createElement("li"); child.innerHtml = "child"; document.getElementById("parent").appendChild(child); }
上述程式碼會多次操作dom,效率比較低,可以改為下面的形式創建documentFragment,將所有元素加入到docuemntFragment不會改變dom結構,最後將其添加到頁面,只進行了一次reflow
#var frag = document.createDocumentFragment(); for(var i=0;i<100:i++){ var child = docuemnt.createElement("li"); child.innerHtml = "child"; frag.appendChild(child); } document.getElementById("parent").appendChild(frag);
2、暂存dom状态信息
当代码中需要多次访问元素的状态信息,在状态不变的情况下我们可以将其暂存到变量中,这样可以避免多次访问dom带来内存的开销,典型的例子就是:
var lis = document.getElementByTagName("li"); for(var i=1;i<lis.length;i++){ //*** } 上述方式会在每一次循环都去访问dom元素,我们可以简单将代码优化如下 var lis = document.getElementByTagName("li"); for(var i=1,j=lis.length ;i<j;i++){ //*** }
3、缩小选择器的查找范围
查找dom元素时尽量避免大面积遍历页面元素,尽量使用精准选择器,或者指定上下文以缩小查找范围,以jquery为例
少用模糊匹配的选择器:例如
$("[name*='_fix']")
,多用诸如id以及逐步缩小范围的复合选择器$("li.active")
等指定上下文:例如
$("#parent .class")
,$(".class",$el)
等
4、使用事件委托
使用场景:一个有大量记录的列表,每条记录都需要绑定点击事件,在鼠标点击后实现某些功能,我们通常的做法是给每条记录都绑定监听事件,这种做法会导致页面会有大量的事件监听器,效率比较低下。
基本原理:我们都知道dom规范中事件是会冒泡的,也就是说在不主动阻止事件冒泡的情况下任何一个元素的事件都会按照dom树的结构逐级冒泡至顶端。而event对象中也提供了event.target(IE下是srcElement)指向事件源,因此我们即使在父级元素上监听该事件也可以找到触发该事件的最原始的元素,这就是委托的基本原理。废话不多说,上示例
$("ul li").bind("click",function(){ alert($(this).attr("data")); })
上述写法其实是给所有的li元素都绑定了click事件来监听鼠标点击每一个元素的事件,这样页面上会有大量的事件监听器。
根据上面介绍的监听事件的原理我们来改写一下
$("ul").bind("click",function(e){ if(e.target.nodeName.toLowerCase() ==="li"){ alert($(e.target).attr("data")); } })
这样一来,我们就可以只添加一个事件监听器去捕获所有li上触发的事件,并做出相应的操作。
当然,我们不必每次都做事件源的判断工作,可以将其抽象一下交给工具类来完成。jquery中的delegate()方法就实现了该功能
语法是这样的$(selector).delegate(childSelector,event,data,function)
,例如:
$("p").delegate("button","click",function(){ $("p").slideToggle(); });
参数说明(引自w3school)
参数 | 描述 |
---|---|
childSelector | 必需。规定要附加事件处理程序的一个或多个子元素。 |
event | 必需。规定附加到元素的一个或多个事件。由空格分隔多个事件值。必须是有效的事件。 |
data | 可选。规定传递到函数的额外数据。 |
function | 必需。规定当事件发生时运行的函数。 |
Tips:事件委托还有一个好处就是,即使在事件绑定之后动态添加的元素上触发的事件同样可以监听到哦,这样就不用在每次动态加入元素到页面后都为其绑定事件了
以上是簡單介紹JavaScript的執行效率的詳細內容。更多資訊請關注PHP中文網其他相關文章!

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

理解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應用程序可讓您從唱歌中為多個客戶提供服務


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

禪工作室 13.0.1
強大的PHP整合開發環境

WebStorm Mac版
好用的JavaScript開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

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