相关文章
做一些动图 学习eventloop
彻底弄懂js执行机制
1、JavaScript是单线程的语言
2、调用栈 Call Stack
主线程:调用栈,又称作执行栈
- 每调用一个函数,解释器就会把该函数的执行上下文添加到调用栈并开始执行;
- 正在调用栈中执行的函数,如果还调用了其他函数,那么新函数也会被添加到调用栈,并立即执行;
- 当前函数执行完毕后,解释器会将其执行上下文清除调用栈,继续执行剩余执行上下文中的剩余代码;
- 但分配的调用栈空间被占满,会引发”堆栈溢出“的报错。
3、同步任务与异步任务
异步任务
异步任务是无法立即得到结果,比如请求接口,每个接口都会有一定的响应时间,根据网速、服务器等等因素决定,再比如定时器,它需要固定时间后才会返回结果。
而异步任务的执行,首先它依旧会进入调用栈中,然后发起调用,然后解释器会将其响应回调任务放入一个任务队列,紧接着调用栈会将这个任务移除。当主线程清空后,即所有同步任务结束后,解释器会读取任务队列,并依次将已完成的异步任务加入调用栈中并执行。
这里有个重点,就是异步任务不是直接进入任务队列的。
4、异步任务分为宏任务与微任务
步任务的执行也是需要按顺序的,队列的属性就是先进先出(FIFO,First in First Out),因此异步任务会按照进入队列的顺序依次执行。
但在一些场景下,如果只按照进入队列的顺序依次执行的话,也会出问题。比如队列先进入一个一小时的定时器,接着再进入一个请求接口函数,而如果根据进入队列的顺序执行的话,请求接口函数可能需要一个小时后才会响应数据。
因此浏览器就会将异步任务分为宏任务和微任务,然后按照事件循环的机制去执行,因此不同的任务会有不同的执行优先级,具体会在事件循环讲到。
这个其实就可以解释了下列代码为什么后面的定时器会比前面的定时器先执行。
因为后者的定时器会先被推进宏任务队列,而前者会之后到点了再被推入宏任务队列。
5、宏任务
setTimeout
setInterval
js主代码
setImmediate(Node)
requestAnimationFrame(浏览器)
6、微任务
process.nextTick
Promise的then方法
- 微任务设计的目的简单讲就是为了插队!
- 微任务在宏任务后调用,微任务会在下一个宏任务执行之前全部处理完再执行EventLoop
- 所以如果有新的宏任务需要等待上一个eventLoop中的微任务执行完,这时如果你不想等到下一个宏任务之后执行某个事
- 你可以使用微任务的方式将你要做的插到当前eventloop中的微任务中,待所有微任务执行完毕再去开启下一个新的宏任务
7、事件循环 Event Loop
事件循环的具体流程如下:
- 从宏任务队列中,按照入队顺序,找到第一个执行的宏任务,放入调用栈,开始执行;
- 执行完该宏任务下所有同步任务后,即调用栈清空后,该宏任务被推出宏任务队列,然后微任务队列开始按照入队顺序,依次执行其中的微任务,直至微任务队列清空为止;
- 当微任务队列清空后,一个事件循环结束;接着从宏任务队列中,找到下一个执行的宏任务,开始第二个事件循环,直至宏任务队列清空为止。
这里有几个重点:
当我们第一次执行的时候,解释器会将整体代码script放入宏任务队列中,因此事件循环是从第一个宏任务开始的;
如果在执行微任务的过程中,产生新的微任务添加到微任务队列中,也需要一起清空;微任务队列没清空之前,是不会执行下一个宏任务的。
8、示例
console.log('script start')
async function async1() { //语法糖 async2()执行完毕 才执行下面 会加入在微观任务里面
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2 end')
}
async1()
setTimeout(function () {
console.log("setTimeout100")
}, 100)
setTimeout(function () {
console.log("setTimeout")
}, 0)
new Promise(resolve => {
console.log('promise')
resolve()
}).then(function () {
console.log("promise1")
})
.then(function () {
console.log("promise2")
})
console.log('script end')
延申 宏任务 && 微任务 && async && await
重点看 详解promise、async和await的执行顺序
宏任务 && 微任务 && async && await
微任务和宏任务的执行顺序