目录
一、是什么
二、同步任务和异步任务
三、宏任务和微任务
小结:微任务是跟屁虫,一直跟着当前宏任务后面代码执行到一个微任务就跟上,一个接着一个。
例子理解:
五、题目巩固
六、总结
一、是什么
首先JavaScript是一种单线程语言,同一时间内只能做一件事情,所有的任务都需要排队完成。这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环。
为什么JavaScript不能有多个线程呢?
作为浏览器脚本语言,JavaScript的主要用途是与用户互动以及操作dom节点。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,当JavaScript同时有两个线程,一个是在A节点上添加内容,另一个是删除A节点,这个时候浏览器不知道应该以哪个为准。
为了避免这种复杂性,因此JavaScript只能是单线程。
二、同步任务和异步任务
在JavaScript
中,所有的任务都可以分为
- 同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
- 异步任务:异步执行的任务,比如
ajax
网络请求,setTimeout
定时函数等
同步任务进入主线程,即主执行栈,异步任务进入任务队列,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。
三、宏任务和微任务
异步任务又分为宏任务和微任务
常见的宏任务:
- script(整体代码)
- setTimeout
- setInterval
- postMessage、MessageChannel
- setImmediate、I/O(Node.js)
- UI交互事件
- ajax请求
常见的微任务:
-
Promise.then
-
MutaionObserver
-
process.nextTick(Node.js)
任务的优先级: process.nextTick > promise.then > setTimeout > setlmmediate
小结:微任务是跟屁虫,一直跟着当前宏任务后面代码执行到一个微任务就跟上,一个接着一个。
例子理解:
五、题目巩固
console.log(1)
setTimeout(()=>{
console.log(2)
}, 0)
new Promise((resolve, reject)=>{
console.log('new Promise')
resolve()
}).then(()=>{
console.log('then')
})
console.log(3)
流程如下:
// 遇到 console.log(1) ,直接打印 1
// 遇到定时器,属于新的宏任务,留着后面执行
// 遇到 new Promise,这个是直接执行的,打印 'new Promise'
// .then 属于微任务,放入微任务队列,后面再执行
// 遇到 console.log(3) 直接打印 3
// 好了本轮宏任务执行完毕,现在去微任务列表查看是否有微任务,发现 .then 的回调,执行它,打印 'then'
// 当一次宏任务执行完,再去执行新的宏任务,这里就剩一个定时器的宏任务了,执行它,打印 2
六、总结
事件的循环机制规定了执行代码的顺序
- 先执行同步代码;
- 遇到异步宏任务则将异步宏任务放进宏任务队列中;
- 遇到异步微任务则将异步微任务放进微任务队列中;
- 当script整体代码所有同步代码执行完毕后,再将异步微任务从【任务队列】中调入【主线程】执行;
- 微任务执行完毕后再将异步宏任务从【任务队列】中调入【主线程】执行;微任务再跟着当前宏任务后面,代码执行到一个微任务就跟上,一个接着一个。
- 一直循环到所有任务执行完毕。