1.javascript是单线程的语言
javascript是一门单线程执行的编程语言。也就是说,同一时间只能做一件事情。
如下:如果有多个任务要执行,执行其他任务时,其他任务都要进行等待
52.png1.1 单线程执行任务队列的问题
如果前一个任务非常耗时,则后续的任务不得不一直等待,从而导致程序假死的问题。
2.同步任务和异步任务
为了防止某个耗时任务导致程序假死的问题,javascript把待执行的任务分为了两类。
- 同步任务
- 又叫做 非耗时任务,指的是在主线程上排队执行的那些任务
- 只有前一个任务执行完毕,才能执行后一个任务
- 异步任务
- 又叫做非耗时任务,异步任务由javascript委托给宿主环境进行执行
- 当异步任务执行完成之后,会通知javascript主线程执行异步任务的回调函数
2.1 同步任务和异步任务的执行过程
53.png- 同步任务由javascript主线程次序执行
- 异步任务委托给宿主环境执行
- 已完成的异步任务对应的回调函数,会被加入到任务队列中等待执行
- javascript主线程的执行栈被清空后,会读取任务队列中的回调函数,次序执行。
- javascript主线程不断重复上面的第4步
js的主线程会从自己的执行栈中去执行栈中的所有任务,当发现任务是同步任务时,js会自己进行执行。如果是异步任务,会委托给宿主环境执行。当js发现自己的执行栈中被执行完后,会从任务队列中按顺序把对应的回调函数取出来放入栈中,按顺序执行。
3.EventLoop的基本概念
javascript主线程从“任务队列”中读取异步任务回调函数,放到执行栈中依次执行。这个过程是循环不断的,所以整个的这种运行机制又称为EventLoop(事件循环)。
3.1 结合EventLoop分析输出顺序
import thenFs from "then-fs";
console.log("A");
thenFs.readFile("./studyPrommise/files/1.txt","utf8").then(res=>{console.log("B");})
setTimeout(()=>{
console.log("C");
},0)
console.log("D");
- 最终的结果是 A D C B
- 因为主线程上只有A和D,是同步任务,所以会依次执行,而B、C是异步任务让js委托给宿主环境执行。
- 然后定时器,只是延时了0秒,所以就会让宿主环境立即执行,然后返回一个回调函数,等主线程空闲时执行。
4.宏任务和微任务
javascript对异步任务又做了进一步的划分,分为了两类,
-
宏任务(macrotask)
- 异步Ajax请求
- setTimeOut、setInterval
- 文件操作
- 其他宏任务
-
微任务(microtask)
- Promise.then、.catch、和.finally
- process.nextTick
- 其他微任务
4.1 宏任务和微任务的执行顺序
55.png- 每个宏任务执行完后,都会检查是否存在待执行的微任务
- 如果有,则会将所有待执行的微任务执行完,再执行下一个宏任务
- 宏任务和微任务是交替执行的
4.2 根据宏任务和微任务分析代码输出的顺序
setTimeout(()=>{
console.log(1);
})
new Promise(function(resolve){
console.log(2);
resolve()
}).then(res=>{
console.log(3);
})
console.log(4);
最后的结果是 2 4 3 1
- setTimeout是一个宏任务,
- new Promise()是一个同步任务,.then()是一个微任务
- console.log(4)是一个同步任务
所以执行的顺序是:执行的准则是 先执行同步任务,再去任务队列中读取回调函数放入执行栈中,按次序执行。但异步任务中:先执行微任务,再执行宏任务
- new Promise()操作
- console.log(4)
- .then()
- setTimeout
4.3 经典面试题
56.png先来分析同步任务和异步任务,最后来分析异步任务中的宏任务和微任务
- 第1行是同步任务1
- 第3-10行是异步任务1(宏任务)
- 第12-15行是同步任务2,也就是new Promise()这一部分
- 第15-17行是异步任务2(微任务)
- 第20-28行是异步任务3(宏任务)
所以执行顺序是:同步任务js本身自身处理,而异步任务交给宿主环境执行
js本身处理的过程:
- 执行同步任务1 :输出1
- 执行同步任务2:输出 5
- 同步任务执行完
- 从任务队列中取出执行完对应的回调函数,放入执行栈中,依次执行
宿主环境处理的过程
- 先执行异步任务2,执行异步任务2,并返回到任务队列中,待主线程执行 输出 6
- 看是否存在待执行的微任务,发现没有,按次序执行宏任务
- 先执行 异步任务1 ,并返回到任务队列中,待主线程执行输出 2 3 4
- 在执行异步任务3 并返回到任务队列中,待主线程执行输出 7 8 9
所以总的输出结果是: 1 5 6 2 3 4 7 8 9
网友评论