

-
javascript事件循环结构 主要组成:执行栈、堆内存、消息队列
执行栈(stack):存储并且执行同步任务,等到同步任务执行完,执行栈会清空,也就是执行栈处于空闲状态,执行栈再执行消息队列里的异步任务。*执行栈遵循的是先进先出原则
堆内存(heap):存储变量和对象
消息队列(queue):消息队列分为宏任务队列和微任务队列,存放异步任务,异步任务主要包括:DOM事件监听、计时器(setTimeout)、网络请求(ajax)
-
事件循环的过程
(1)任务进入执行栈,先判断是同步任务还是异步任务,如果是同步任务,主线程就会把同步任务放到执行栈中执行,遵从先进先出的原则;如果是异步任务,交给webAPIS处理,存储到消息队列中,等待执行
(2)同步任务全部执行完以后,主线程读取消息队列,先去执行消息队列里的微任务,微任务全部执行完,释放清空,然后再去开始执行宏任务队列
(3)循环,重复上述2步骤
-
宏任务和微任务

(1)宏任务:setTimeout、setInterval、I/O
(2)微任务:promise
执行栈执行完同步任务后,释放清空执行栈,处于空闲状态,主线程就会去读取消息队列,消息队列里有任务,执行栈就会去执行消息队列
具体步骤:执行栈执行完同步任务后,判断是否有可执行的微任务,有微任务则执行所有微任务,执行完微任务,开始新的宏任务,开始下一次循环;没有微任务则直接开始执行下一个宏任务,开始下一次循环;执行完宏任务,再去判断有没有微任务,重复上述步骤。异步任务中(即消息队列中),执行下一个宏任务之前,会执行完本次循环中的所有微任务
-
例子
console.log('start')
const interval = setInterval(() => {
console.log('setInterval')
}, 0)
setTimeout(() => {
console.log('setTimeout 1')
Promise.resolve().then(() => {
console.log('promise 3')
}).then(() => {
console.log('promise 4')
}).then(() => {
setTimeout(() => {
console.log('setTimeout 2')
Promise.resolve().then(() => {
console.log('promise 5')
}).then(() => {
console.log('promise 6')
}).then(() => {
clearInterval(interval)
})
}, 0)
})
}, 0)
Promise.resolve().then(() => {
console.log('promise 1')
}).then(() => {
console.log('promise 2')
})
第一轮:
整段代码被当做macrotask执行
console.log('start') 打印‘start’
interval = setInterval(() => {})回调函数()=>{}放入消息队列的macrotask中,此时消息队列的macrotask队列为[interval]
setTimeout(()=>{})回调函数()=>{}放入消息队列的macrotask,此时消息队列的macrotask队列为[interval, setTimeout1]
执行promise,并且调用resolve方法,触发了回调函数,这时候把回调函数添加到消息队列中的microtask中,此时microtask为['promise1', 'promise2']
执行栈执行完同步任务,释放清空,处于空闲状态
第一轮执行结果:'start'
第二轮:
先执行消息队列中的microtask queue中的回调函数,打印promise1,promise2;microtask queue为空
从macrotask queue [interval,setTimeout1]中取出interval,打印setInterval,执行完释放掉,此时macrotask queue [setTimeout1]
setInterval的回调函数添加到消息队列的macrotask queue中,此时macrotask为[setTimeout1, setInterval]
执行栈为空,microtask queue为空,开始下一轮循环
第二轮执行结果:'start' 'promise1' 'promise2' 'setInterval'
第三轮:
取出macrotask queue中的最早的任务,setTimeout1,打印setTimeout1,释放掉setTimeout1,此时macrotask queue为[setInterval]
执行promise,调用了resolve方法,触发回调,回调函数被存放在microtask queue中,此时microtask queue为[promise3, promise4, setTimeout2]
执行栈为空,放入执行栈执行microtask queue,打印出promise3, promise4。setTimeout2是异步函数,setTimeout2的回调函数放入消息队列中的macrotask queue中,此时macrotask queue为[setInterval, setTimeout2]
microtask为空,执行栈为空
第三轮执行结果:'start' 'promise1' 'promise2' 'setInterval' 'setTimeout1' 'promise3' 'promise4'
第四轮:
取出macrotask queue中最早的任务,setInterval,执行setInterval,打印出setInterval,释放掉setInterval,此时macrotask queue为[setTimeout2],执行栈为空
将setInterval放入macrotask queue中,此时macrotask queue为[setTimeout2, setInterval]
执行栈为空,microtask queue为空,开始下一轮循环
第四轮执行结果:'start' 'promise1' 'promise2' 'setInterval' 'setTimeout1' 'promise3' 'promise4' 'setInterval'
第五轮
取出macrotask queue 中最早的任务setTimeout2,执行setTimeout2,打印出setTimeout2,此时macrotask queue为[setInterval]
执行promise,调用resolve方法,触发回调,回调函数被存放在microtask queue中,此时microtask queue为[promise5, promise6, clearInterval]
执行消息队里的microtask queue中的所有回调函数,打印出'promise5', 'promise6',清空interval
此时执行栈为空,macrotask queue为空,microtask task为空,任务结束
第五轮执行结果:'start' 'promise1' 'promise2' 'setInterval' 'setTimeout1' 'promise3' 'promise4' 'setInterval' 'setTimeout2' 'promise5' 'promise6'