原生addEventListener比jq的on慢了60倍, 為什麼?

原生的addEventListener比jq的on慢了60倍

為什麼會差這麼多?

兩者分別執行10^5次, jq用了762毫秒, 原生用了45165毫秒


因為對每個元素,jQuery 只調用一次 addEventListener,在其回調中維護了一個隊列。你每次通過 on 追加事件監聽時只是把處理函數加入那個隊列而已。你第二個 case 中每次都會直接調用 addEventListener,所以很慢。

---

補充一下, @二貨 說的是對的,單次 addEventListener 的耗時受已綁定的回調函數數量影響。而 jQuery.on 的耗時是穩定的。不在性能測試的場景下跑,addEventListener 的性能應該是優於 jQuery.on 的。原問題中的 case,每次綁定的回調函數都是新聲明的,導致在性能測試場景下,元素上綁定的回調函數越來越多,這在實際場景下是很難遇到的。如果是重複綁定同一個函數實例,addEventListener 去重以後耗時會很低。

具體可以看下這個性能測試:Event Performance。


我們看一下standard的描述:Document Object Model Events

addEventListener

This method allows the registration of event listeners on the event target. If an EventListener is added to an EventTarget while it is processing an event, it will not be triggered by the current actions but may be triggered during a later stage of event flow, such as the bubbling phase.

If multiple identical EventListeners are registered on the same EventTarget with the same parameters the duplicate instances are discarded. They do not cause the EventListener to be called twice and since they are discarded they do not need to be removed with the removeEventListener method.

看到重點了嘛?addEventListener方法會對綁定事件進行去重。

所以當你使用原生方法綁定事件時,它會首先檢查function是否重複綁定。如果沒有才進行綁定。而jQuery的on是不進行去重的

你試試以下的代碼,再看看結果?

var i;
function test() {};
console.time("t1");
for (i = 0 ; i &< 1000000 ; i += 1) $(document.querySelector("a")).on("click", test); console.timeEnd("t1"); console.time("t2"); for (i = 0 ; i &< 1000000 ; i += 1) document.querySelector("a").addEventListener("click", test); console.timeEnd("t2");

PS:測試時不要使用let,會降低對比效果哦~


所以需要事件代理呀[/逃]


贊同@二貨 的答案,我總結一下重點

jq不去重,時間複雜度為O(n);

addEventListener會去重,每次加入一個新的fn,都會遍歷比較,總時間複雜度是O(n^2)

其中n為fn的總數量


當添加很多監聽事件的時候會降低JavaScript的執行效率,我是小白不一定對


推薦閱讀:

前端打包如何在減少請求數與利用並行下載之間找到最優解?
怎麼樣向不懂前端的人介紹前端?
前端開發中,對圖片的優化技巧有哪些?
Google 的 HTML 代碼看著很亂,為什麼要寫成這樣呢?
網頁 head 標籤中的 JS 和 CSS,哪種文件放在前面,哪种放在後面比較好?

TAG:前端開發 | jQuery | 前端性能優化 |