javascript
hook 循环点击事件用哪个_JS 事件循环 event loop,看完你可以答对 90% 的事件循环题...
本文不保證能說明透徹,因為它本來就存在著混亂,但力求講到點子上。
比較下面這幾個的執行順序setTimeout
setInterval
setImmediate (nodejs 支持,
new Promise(cb) 和 promise.then(cb)(promise 是 Promiose 的實例)
process.nextTick(nodejs)
還有一些另外的(暫時不考慮)socket.on('close', cb) close callback(nodejs)
分類
同步執行
new Promise(cb) cb 代碼會同步執行,其實不屬于考慮范疇了
microTask 微任務process.nextTick tickTask
promise.then(cb) microTask
microTask (在 nodejs)可以進一步劃分為 tickTask 和 microTask,都是微任務隊列,同類型的微任務先進先執行
優先級是 tickTask > microTask
macroTask 宏任務setTimeout
setInterval 優先級同 setTimeout,誰先被推到 timers 隊列誰就先執行
setImmediate
在不同類型宏任務切換的間隙,一旦微任務隊列有任務則會把微任務隊列先執行完,然后繼續執行下一個類型的宏任務隊列。(注意是切換的時候,如果已經進入執行階段是讓該類型的宏任務執行完然后檢查微任務隊列,如果宏任務執行時又加入了同類型的宏任務,則會在下一個循環里面執行)
進入 timers 或者 check 或者其他的宏任務隊列時,如果 microTask 任務隊列中沒有任務,則會在執行完優先執行的宏任務隊列之后再檢查 microTask 任務隊列(注意:如果某個 macroTask 執行時推入了新的 microTask,它依然會先把這個類型的宏任務隊列執行完,然后切換下一個類型宏任務隊列時先執行微任務),如果有則執行完 microTask,然后進入下一個類型的 macroTask 隊列
這里有一個非確定情況,setImmediate 和 setTimeout 的執行順序在 nodejs 中不是固定的(nodejs 開發者這么說)。? For example, if we run the following script which is not within an I/O cycle (i.e. the main module), the order in which the two timers are executed is non-deterministic, as it is bound by the performance of the process
”
做個測試,下面的執行是不確定的,沒有實際的意義
setTimeout(() => {
console.log('1 setTimeout')
setTimeout(() => {
console.log('2 setTimeout')
}, 0)
setImmediate(() => {
console.log('3 setImmediate')
})
}, 0)
setImmediate(() => {
console.log('4 setImmediate')
})
nodejs
可能
4 setImmediate
1 setTimeout
3 setImmediate
2 setTimeout
也可能
1 setTimeout
4 setImmediate
3 setImmediate
2 setTimeout
setTimeout 有一個隱形前提,它的第二個參數,也就是延遲執行的時間,最小是 4ms,即使指定的 0,另外注意它是 n ms 之后才可能執行,并不是 n ms 時就會執行,它的執行時間是不確定的,只能知道在 n ms 之前它不會執行。
setInterval 回調內如果是一個 while 循環,即使時間設定的 0,它也不會推無限多個回調到 timers 隊列中,而是要等到這個執行完,才會把下一個回調推入 timers 隊列,用 while 執行 2S 之后,清除掉 interval,發現回調只執行了一次,而不是執行很多次。
看下面的例子,這說明 setInterval 會推一個回調到 timers 隊列,然后執行,然后再推下一個回調。
let count = 0
setTimeout(() => {
console.log('1 setTimeout')
}, 0)
const i = setInterval(() => {
console.log('2 setInterval')
count++
if (count === 5) {
clearInterval(i)
}
setTimeout(() => {
console.log('3 setTimeout ', count)
}, 0)
}, 0)
setTimeout(() => {
console.log('4 setTimeout')
}, 0)
---
1 setTimeout
2 setInterval
4 setTimeout
3 setTimeout 1
2 setInterval
3 setTimeout 2
2 setInterval
3 setTimeout 3
2 setInterval
3 setTimeout 4
2 setInterval
3 setTimeout 5
nodejs 事件循環
上述基本都是 macroTask 宏任務
setTimeout(() => {
console.log('1 setTimeout')
setTimeout(() => {
console.log('2 setTimeout')
}, 0)
setImmediate(() => {
console.log('3 setImmediate')
})
setTimeout(() => {
console.log('4 setTimeout')
}, 0)
setImmediate(() => {
console.log('5 setImmediate')
})
}, 0)
這個結果說明執行過程是整個隊列執行完再執行下一個隊列下面結果說明在同一事件循環內, check 隊列會執行完之后再去執行 timers 隊列。(check 未必比 timers 快)
1 setTimeout
3 setImmediate
5 setImmediate
2 setTimeout
4 setTimeout
如果在 check 隊列執行期間推入 microTask 任務,那就先讓當前 check 隊列執行完,然后再執行 microTask,再執行 timers 隊列。
setTimeout(() => {
console.log('1 setTimeout')
setTimeout(() => {
console.log('2 setTimeout')
}, 0)
setImmediate(() => {
console.log('3 setImmediate')
new Promise(res => res()).then(() => {
console.log('4 promise')
})
process.nextTick(() => {
console.log('5 nextTick')
})
})
setTimeout(() => {
console.log('6 setTimeout')
}, 0)
setImmediate(() => {
console.log('7 setImmediate')
})
}, 0)
執行結果,兩個 setImmediate 被放到 check 隊列,check 隊列中的 setImmediate 要先全部執行完,然后再下一步,而下一步過程中 microTask 就會執行。
1 setTimeout
3 setImmediate
7 setImmediate
5 nextTick
4 promise
2 setTimeout
6 setTimeout
注意下面代碼和上面代碼的區別
setTimeout(() => {
console.log('1 setTimeout')
setTimeout(() => {
console.log('2 setTimeout')
}, 0)
setImmediate(() => {
console.log('3 setImmediate')
})
new Promise(res => res()).then(() => {
console.log('4 promise')
})
process.nextTick(() => {
console.log('5 nextTick')
})
setTimeout(() => {
console.log('6 setTimeout')
}, 0)
setImmediate(() => {
console.log('7 setImmediate')
})
}, 0)
---
1 setTimeout
5 nextTick
4 promise
3 setImmediate
7 setImmediate
2 setTimeout
6 setTimeout
題目
題目 1
setTimeout setInterval 是不是相同優先級?是否被推到同一個隊列
setTimeout(() => {
console.log('1 timeout')
}, 0)
setInterval(() => {
console.log('2 interval')
}, 0)
setTimeout(() => {
console.log('3 timeout')
}, 0)
setInterval(() => {
console.log('4 interval')
}, 0)
setTimeout(() => {
console.log('5 timeout')
}, 0)
題目 2
setTimeout(() => {
console.log('1 setTimeout')
setTimeout(() => {
console.log('2 setTimeout')
}, 0)
setImmediate(() => {
console.log('3 setImmediate')
setImmediate(() => {
console.log('4 setImmediate')
})
process.nextTick(() => {
console.log('5 nextTick')
})
})
setImmediate(() => {
console.log('7 setImmediate')
})
setTimeout(() => {
console.log('8 setTimeout')
}, 0)
}, 0)
總結
微任務(microTask)是大爺,宏任務(macroTask)得讓著微任務,但是一旦讓一個類型的宏任務開始執行,那就得等這個類型的宏任務執行完,然后才能執行微任務!!!在宏任務中被推入隊列的宏任務得在下一輪才能開始執行,這一輪沒新宏任務的份。
歡迎大家關注我的掘金和公眾號,算法、TypeScript、React 及其生態源碼定期講解。
總結
以上是生活随笔為你收集整理的hook 循环点击事件用哪个_JS 事件循环 event loop,看完你可以答对 90% 的事件循环题...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: centos8安装mysql_CentO
- 下一篇: svg入门经典pdf_机器学习最好的入门