概述
为什么javascript是单线程的?
为什么需要存在异步任务?
JavaScript怎么处理异步任务的?
宏任务是什么?
微任务是什么?
同步任务,异步任务,宏任务,微任务 执行次序?
解答
1.为什么JavaScript是单线程?
因为JavaScript设计之初是为了服务器浏览器,而浏览器如果存在多线程,不同进程针对相同一个DOM进行不同操作,一个删除,一个修改,则存在矛盾冲突。
后续web Worker出现,虽然可以利用多核CPU的计算能力,创建多线程,但是子线程受控于主线程,且无法操作DOM,JavaScript依然为单线程的存在
2.为什么需要存在异步任务?
以浏览器前后端的I/O操作为例,是一个耗时操作,如果都是同步任务,那么会阻塞后续任务的执行,用户体验不友好
3.JavaScript怎么处理异步任务的?
对于一段JS代码,有同步任务(synchronous),也存在异步任务(asynchronous)的情况下,
存在的同步任务,会进入在主进程的执行栈(execution contextstack)中,优先执行
存在的异步任务,会进入事件表(event table),
异步任务在事件表(event table)中注册函数,当满足触发条件后,被推入事件队列(event queue)
当主进程任务全部执行完毕后,
会查看 事件队列(event queue)有无任务,
有则执行
没有则继续轮循(loop),直到所有的事件表(event table)中注册函数都执行完毕

4.宏任务 微任务
宏任务、微任务都依附于执行环境(针对JavaScript来说,浏览器环境和node环境)
宏任务:主要任务,优先级高于微任务
微任务:次要任务
区分:
宏任务
主体script , setTimeout , setInterval , new Promise()
微任务
Promise.then , promise.nextTick
优先执行可执行的宏任务,执行完毕后查看有无可执行的微任务,没有微任务,则继续寻找可执行的宏任务

例子:
setTimeout(()=>{ console.log(4) },0)
new Promise(resolve => {
resolve()
console.log(1)
}).then(() => {
console.log(3.1)
}).then(() => {
console.log(3.2)
}).then(() => {
console.log(3.3)
})
console.log(2)

如图结果所示:
Promise实例化阶段是宏任务,setTimeout也是宏任务(但是他是异步的),所以输出了1,
Promise的then阶段是微任务,跳过看后续有无可执行宏任务,所以到了log(2)的部分,因此输出的2
查看有无可执行的宏任务,因为异步的原因(即便是延迟0秒),还是不可执行状态
查看有无可执行的微任务,所以log了3.1、3.2、3.3
继续查看有无微任务,没有,查找可执行的宏任务,因为延迟时间到了,推进了事件队列(event queue),所以执行新的宏任务log(4),因此输出了4
纵观这个demo,可以简单总结
同步(宏)任务 > 同步(微)任务 > 异步任务
为了严谨,考虑到同步(宏)任务也是耗时的,比如:
var num=0;
console.time('任务1');
for(var i=0; i<100000;i++){
num+=1;
}
console.timeEnd('任务1');
console.log(num); //100000
//任务1:64 毫秒 - 倒计时结束
如果宏任务的耗时远超过异步任务,那么执行顺序会怎样呢??

再次总结
浏览器环境以及node环境所示上图,
异步任务自身性质决定了,只要主进程(宏、微)任务没跑完,就要一直等待下去,即便早已过了异步任务的延迟时间
再次总结:
同步(宏)任务 > 同步(微)任务 > 异步任务
网友评论