JavaScript 运行机制详解(宏任务与微任务的解读 eventLoop)
前言
1. 为什么JavaScript是单线程?
2. 任务队列
3. 微任务,宏任务
一、为什么JavaScript是单线程?
js是单线程的,也就代表js只能一件事情一件事情执行,那如果一件事情执行时间太久,后面要执行的就需要等待,需要等前面的事情执行完成,后面的才会执行。
二、任务队列
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着
如JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。
于是,所有任务可以分成两种,一种是同步任务,另一种是异步任务。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
*事件循环(Event Loop)
- -主线程先判断任务类型
-1.如果是同步任务,主线程自己执行
-2.如果是异步任务,交给宿主环境(浏览器)执行
(2)主线程之外,还存在一个"任务队列"(task queue)。每个异步执行完后,会将回调放进任务队列,先执行完成的先放进任务队列,依次放入。 | |
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",会取任务队列中的任务,由于任务队列里是依次放入进来的,所以取得时候也会先取先进来的,也就是先进先出原则。 | |
(4)主线程不断重复上面的第三步。 |
如图展示
三,微任务,宏任务
微任务与宏任务
概念:
宿主环境提供的叫宏任务,由语言标准提供的叫微任务
-
宿主环境:
简单来说就是能使javascript完美运行的环境,只要能完美运行javascript的载体就是javascript的宿主环境。目前我们常见的两种宿主环境有浏览器和node。
我们都知道window是我们一直使用的全局对象,但其实global 是 javascript
运行时所在宿主环境提供的全局对象
宿主环境内所有的内建或自定义的变量/函数都是 global/window 这个全局对象的属性/方法,而由宿主环境提供的也叫宏任务。 -
语言标准:
我们都知道JavaScript是一种编程语言,但其实JavaScript由ECMA制定标准,称之为ECMAScript,所以由语言标准提供的就是微任务,比如ES6提供的promise。
,promise是ES6语言标准提供的,定时器是宿主环境提供的,所以promise会比定时器更早执行。
常见宏任务与微任务
宏任务
宏任务
- setImmediate(Node环境下独有)
- requestAnimationFrame(浏览器环境独有)
- I/O
- UI rendering(浏览器独有)
微任务
微任务,
- Object.observe
- MutationObserver
- process.nextTick(Node环境独有)
微任务和宏任务的工作流程(总结:有微则微,无微则宏)
先执行宏任务
- 宏任务执行完后
- 看微任务队列是否有微任务
- 没有微任务执行下一个宏任务
- 有微任务将所有微任务执行
- 执行完微任务,执行下一个宏任务
4.理解理论,做这套面试题再进一步理解
console.log(1)
setTimeout(function(){
console.log(2)
}, 0)
new Promise(function(resolve){
console.log(3)
resolve()
}).then(function(){
console.log(4)
})
console.log(5)
答案:1、3、5、4、2
// 请将下面这段代码的执行结果写出来
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1')
resolve();
}).then(function () {
console.log('promise2')
})
console.log('script end')
这段代码的执行结果会是什么呢?
知识点:
解析:
1.await 执行完后,。async 标记的函数会返回一个 Promise 对象,等promise对面都执行完后再执行下面的语句**
2.await asyn2()后面的代码console.log(")相当于.then的微任务
最终答案为
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout