欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 前端技术 > javascript >内容正文

javascript

hook 循环点击事件用哪个_JS 事件循环 event loop,看完你可以答对 90% 的事件循环题...

发布时间:2024/9/27 javascript 51 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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% 的事件循环题...的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。