关于三者之间的区别,首先要了解js运行机制,js是单线程,同一时间只能做一件事,单线程就意味着,所有任务需要排队,前一个任务执行完,后一个才能执行。于是,所有任务分成了两种,一种是同步任务,一种是异步任务 同步任务:主线程上排队的任务,只有前一个执行完才能执行后一个 异步任务:异步任务指的是不进入主线程,而进入任务队列(task)的任务,只有任务队列通知主线程,某个任务可以执行了,该任务才会进入主线程执行
所有同步任务都在主线程上执行,形成一个执行栈 主线程外还存在一个任务队列,只要异步任务有了运行结果,就在任务队列中放置一个事件 一旦执行栈中所有同步任务执行完毕,系统会读取任务队列,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行 主线程不断重复上面的第三步
任务队列
任务队列是一个事件的队列,完成一项任务就在任务队列中添加一个事件,表示相关的异步任务可以进入执行栈。主线程读取任务队列,就是读取里面有哪些事件 任务队列中事件,除了IO设备的时间以外,还包括一些用户产生的事件(鼠标点击、页面滚动等), 所谓回调函数,就是哪些会被主线程挂起来的代码,异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数
事件循环
主线程从任务队列中读取事件,这个过程是循环不断,所以整个的这种运行机制又称为Event Loop
宏任务
宏任务微任务并不是异步任务的子集,而是除了同步异步之外,更宽泛的对执行栈任务的分类。 宏任务可以理解为每次进入执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行) 浏览器为了能够使得JS内部macrotask与DOM任务能够有序的执行,会在一个macrotask执行结束后,在下一个macrotask 执行开始前,对页面进行重新渲染,流程如下:
macrotask->渲染->macrotask->...
宏任务包括:script(整体代码)、 setTimeout、 setInterval I/O、 UI交互事件 、postMessage、 MessageChannel、 setImmediate(Node.js 环境)
微任务
microtask,可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。 所以它的响应速度相比setTimeout(setTimeout是task)会更快,因为无需等渲染。也就是说,在某一个macrotask执行完后,就会将在它执行期间产生的所有microtask都执行完毕(在渲染前)。
微任务包括: Promise.then 、Object.observe、MutaionObserver、process.nextTick(Node.js 环境)
Promise
Promise本身是一个同步的立即执行函数,当在excutor中执行resolve或者reject时,此时是异步操作。会优先执行then/catch等,当主栈完成后才会去执行resolve/reject中存放的方法
console.log('js start')
new Promise((resolve,reject) => {
console.log('promise start')
resolve()
console.log('promise end')
}).then(() => {
console.log('promise then')
})
setTimeout(() => {
console.log('timeout')
},0)
console.log('js end')
// js start > promise start > promise end >js End > promise then > timeout
// new Promise()是一个同步立即执行函数
// promise.then()的回调就是一个task
// promise是resolved或者rejected,那么这个task就放入当前事件循环的微任务队列
// promise是pending这个task就会放入事件循环的宏任务队列
async/await
async函数是一个返回Promise对象,当函数执行的时候,一旦遇到await就会先返回,等到触发的异步操作完成,在执行函数体内后面语句 await的含义为等待,也就是async函数需要等待await后的函数执行并且有了返回结果,才能继续执行下面的代码,await通过返回一个promise对象来实现同步效果
async function async1(){
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2(){
console.log('async2 end')
}
console.log('script start')
// async1返回的是一个Promise,promise是一个同步立即执行函数
async1()
console.log('script end')
// script start > async1 start > async2 end > async1 end > script end