日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

click事件在什么时候出发_剖析setTimeout和click点击事件的触发顺序

發布時間:2024/7/23 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 click事件在什么时候出发_剖析setTimeout和click点击事件的触发顺序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

下面是一段非常簡單的JavaScript代碼

dianji

setTimeout(function () {

alert('timer handler')

}, 2000)

function test () {

document.addEventListener('click', function (e) {

alert('click handler')

}, false)

var startTime = new Date()

while ((new Date()).getTime() - startTime < 5000){}

}

但是當你點擊這個按鈕時,產生的效果可能會讓你有些困惑。下面我們來看下:

頁面打開2s內點擊一次按鈕

這段JavaScript代碼當你在頁面打開2s時間內點擊一次按鈕,效果是這樣的:

頁面卡住大約5s鐘

大約5s后彈出 click handler

點擊彈窗確認后,彈出 timer handler

當你繼續再次點擊頁面中的按鈕,此時依次發生:

頁面卡住大約5s鐘

大約5s后彈出 click handler 一次!

點擊確認后又彈出 click handler 一次。

如果繼續點擊button按鈕,會出現同樣的效果,且 click handler 彈出的次數會依次增加

分析

分析這段代碼來看,點擊按鈕后,代碼執行會進入 test 函數, test函數中首先對 document 對象綁定上了一個 click 事件。然后執行了一個5s的死循環。

此時頁面卡住就是因為這個死循環

ar startTime = new Date()

while ((new Date()).getTime() - startTime < 5000){}

這個死循環會導致js阻塞在這里. 在這5s時間內,2s的定時器其實在第2秒的時候已經定時完成,并把這個完成的事件放入到了任務隊列中;而你在2秒之前點擊的按鈕這個click事件也被瀏覽器放入一個dom事件隊列等待執行。

當5s死循環的時間過去,js引擎開始變成空閑,此時點擊按鈕觸發的這個test處理器執行完畢,js引擎便從事件隊列中取出 click 事件進行執行,當前元素沒有訂閱click那么就冒泡到訂閱了該事件的document進行執行。(會繼續冒泡到document。(本質上冒泡其實是: 瀏覽器取出dom事件中的click事件,然后從target元素開始往上找 看下是否整個網頁中還有元素訂閱了這個click事件)

由于在剛剛test函數執行期間,document對象上綁定上了 click 的監聽,所以此時冒泡上來的 click 會觸發document對象上的 click事件處理器, 因此彈出了 click handler.

當這個 click 冒泡完畢,所有的訂閱者訂閱的處理器都被完全處理完,js線程再次空閑,此時去查看任務隊列中的任務,發現有個2s定時器的任務已經執行完畢,js開始執行定時器的回調函數,所以彈出了 time handler

當你第二次點擊按鈕,再次觸發了 test 函數。 此時test函數內還是做了同樣的事情,但是之前document上已經綁定了一個click的handler函數,所以第二次執行 test函數,會讓 document對象的click處理器變成2個。 因此第二次點擊按鈕 click handler 會彈出2次

頁面打開2s內點擊一次按鈕,然后第3s時點擊頁面空白處2次

這樣操作的效果是這樣的:

頁面卡住大約5s鐘

大約5s后彈出 'click handler'

彈出 'click handler' 第二次

彈出 'click handler' 第三次

彈出 'time handler'

分析

第2點之所以出現在第5點之前,在上文我們已經講過原因了---總之,基本上是因為click觸發的時刻確實就比timer觸發的早,肯定要等click的handler都處理完再執行timer處理器。

但至于第3、4點為什么出現在5之前呢?這個跟2出現在5之前的原因就不一樣了,因為用戶在頁面上的第二次和第三次點擊是在2s鐘之后了,此時timer定時器肯定已經完成了,但是觸發 click handler 依然在 timer handler 之前。 這是為什么呢?

這主要是因為js獲取任務來執行時, 點擊事件的任務隊列 要優先于 timer事件的任務隊列。 具體可參考我的另外一篇文章 瀏覽器的單線程機制和事件循環

在頁面卡住的5s時間內,用戶在頁面上點擊的2次事件會放入比timer更優先的一個macroTask任務隊列。由于js空閑時優先要把click事件這種更優先的macroTask任務執行完,直到任務隊列為空。所以就出現了上面 click handler 要比 timer handler 更早彈出的效果。

心得

js中事件可以注冊多個handler形成handlers. handlers類似于一個處理器的數組。事件觸發后,該事件的handler處理器會被依次執行.

這里舉個跟上面有點區別的例子:假如在某個handler執行的過程中,又給該事件增加了新的handler,那么新增的這個handler不能立即執行。

demo測試代碼:

dianji

function test () {

alert('click handler 1');

/* test函數觸發的過程中,又給按鈕綁定了新的handler; 但本次handlers遍歷執行的過程中,不會執行新加入的這個handler */

/* 因此,首次點擊按鈕, click handler2 不會彈出 */

document.querySelector('#test').addEventListener('click', function (e) {

alert('click handler 2')

}, false);

}

其實這里原理很簡單:因為test元素對象上的事件handlers被觸發執行的時候,類似于把數組拿出來遍歷。你不可能把遍歷數組和修改數組的邏輯同時運行。如:

let a = [1,2,3]

let count = 'x'

a.forEach((item, index) => {

console.log(item)

a.push(count + index)

})

console.log(a)

// 輸出

// 1

// 2

// 3

// [ 1, 2, 3, 'x0', 'x1', 'x2' ]

除非你addEventListener的時候,添加到冒泡的上層元素上。即下面講的第三點。

addEventListener 會給事件不斷增加新的處理器handler

事件處理器handler在執行期間,事件還沒有冒泡。此時還有機會給上層元素綁定事件處理器。

一個事件在冒泡過程中,要等所有訂閱該事件的處理器都處理完畢,js才會去選擇新的任務隊列中的任務來執行。在事件觸發后以及事件的冒泡過程中,會優先執行訂閱了該冒泡事件的處理器,而不會去理會任務隊列。

這一條原理很簡單,只需知道:js在執行同一個dom事件的所有回調處理器的過程是同步的,占用js線程執行的即可。

在事件循環中 microTask 優先于 marcroTask執行,且macroTask中也有不同優先級的隊列,例如dom事件便高于timer。

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的click事件在什么时候出发_剖析setTimeout和click点击事件的触发顺序的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。