# javascript 单线程及异步
首先我们要明确一点,JavaScript不管怎么执行都是单线程工作,也就是说同一个时间只能做一件事。JavaScript的单线程,与它的用途有关,作为浏览器脚本语言,JavaScript的主要用途是与用户交互,以及操作DOM。这决定了它只能是单线程,否则会带来很多复杂的同步问题。为了利用多核CPU的计算能力,虽然HTML5提出了Web Worker,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM和BOM。所以,依然没有改变JavaScript是单线程的本质
既然说Javascript是单线程工作,那怎么还会有异步?这不是自相矛盾吗?
其实,单线程和异步确实不能同时成为一个语言的特性。js选择了成为单线程的语言,所以它本身不可能是异步的,但js的宿主环境(比如浏览器,Node)是多线程的,宿主环境通过某种方式(事件驱动,下文会讲)使得js具备了异步的属性
所以说,一种语言的牛逼往往不是看语言本身,而是看他运行的环境
# EventLoop
我觉得这应该是浏览器语言的核心,掌握EventLoop运行机制对提高对js的认知很有帮助
# 宏任务
javascript是单线程,但浏览器是多线程的,javascript执行在浏览器中,在V8里跑着的一直是一个一个宏任务,就相当于排队打饭一样,一个个人相当于一个个宏任务
执行流程图如下:

console.log(1)
setTimeOut(()=>{
console.log(2)
})
console.log(3)
// 1,3,2
我们发现 在定时器中的输出是最后打印出来的,这就是因为js把定时器当成了一个宏任务,也就是下一个宏任务
# 微任务
当浏览器执行完一个宏任务后,就会看看有没有微任务执行,如果有微任务执行,就会先把当前的微任务执行完,再去执行下一个宏任务
微任务的代表有ajax,回调函数,和Promise
执行流程如下:

主线程从“任务队列”中读取事件,这个过程是循环不断的,所以整个过程的这种运行机制又称为Event Loop(事件循环)
为了好理解,我们举个例子
console.log(1);
setTimeout(()=>{
console.log(2)
})
new Promise((res,req)=>{
console.log(3)
res();
}).then(()=>{
console.log(4)
})
console.log(5)
// 输出: 1 3 5 4 2
1 3 5 可以看做是第一个宏任务,4 为第一个宏任务的微任务,2 为第二个宏任务
# 总结
整个EventLoop的执行原理好比医生和病人看病
假设只有一个医生,大家都排队(主队)看病,医生一次只能看一个(单线程),但是有的病人需要做检查,那医生就给他开单子,让他拿着单子去做检查(异步),这个时候医生也不能等着什么也不干(浪费资源),然后接着看下面的病人,这时,做检查的那个人回来了,就排到了另一队(辅队)。医生在主队每次看完一个病人都要去看看辅队有没有人做完检查(时间轮询),如果有就会先把辅队的病人看完,然后再去主队里看下一个病人。
← this javascript继承 →