js为什么是单线程?
js作为浏览器脚本语言,其主要用途是与用户互动,以及操作DOM。这就决定了它只能是单线程,否则会带来很复杂的同步问题。(假设JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?)
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。因此这个新标准并没有改变JavaScript单线程的本质。
单线程的js如何处理同步任务和异步任务呢?
单线程就意味着所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得等待。因此js语言的设计者将所有任务分成两种,一种是同步任务,另一种是异步任务
同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务
异步任务:不进入主线程、而进入"任务队列"的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
![](https://img.haomeiwen.com/i13091615/b28aa6bd18ce9c6f.png)
执行栈:
执行栈里面存着的都是同步任务,也就是要按顺序执行的任务;
![](https://img.haomeiwen.com/i13091615/4a7a838de1807f4d.png)
看下面代码执行过程帮助理解执行栈
![](https://img.haomeiwen.com/i13091615/7bd045dda6857af8.png)
当我们调用bar函数时,创建了第一个栈帧(C语言中每个栈帧对应着一个未运行完的函数) ,栈帧中包含了bar的参数和局部变量。当bar调用foo时,第二个栈帧就被创建,并被压到第一个帧之上,栈帧中包含了foo的参数和局部变量。当foo返回时,最上层的帧就被弹出栈(剩下bar函数的调用帧 )。当bar返回的时候,栈就空了(栈是箱子,先进后出)
任务队列:
任务队列中存着的是异步任务,这些异步任务一定要等到执行栈清空后才会执行。
1. 如果是异步任务,会先到事件列表中注册函数。
2. 如果事件列表中的事件触发了,会将这个函数移入到任务队列中(DOM操作对应DOM事件,资源加载操作对应加载事件,定时器操作可以看做对应一个“时间到了”的事件)
![](https://img.haomeiwen.com/i13091615/947027f4fb280482.png)
宏任务与微任务:
任务队列又分为宏任务和微任务,执行顺序如下图所示
macro-task(宏任务) ---->seTimeout ,setInterval,js的整体代码
micro-task(微任务) ---->Promise
![](https://img.haomeiwen.com/i13091615/23ba26bd94381f34.png)
这里提下为什么要用到Microtask:减少更新时的渲染次数
因为根据HTML标准, 在每个宏任务运行完以后,UI都会重新渲染。如果在microtask中就完成数据更新,当 macro-task结束就可以得到最新的UI了。如果新建一个 macro-task来做数据更新的话,那么渲染会执行两次
看完上面的内容后,再来一张总结图
![](https://img.haomeiwen.com/i13091615/4aed8e04793ef4c0.png)
事件循环:
js调控同步和异步任务的机制被称为事件循环
从代码执行顺序的角度来看,程序最开始是按代码顺序执行代码的,遇到同步任务,立刻执行;遇到异步任务,则只是调用异步函数发起异步请求。此时异步任务开始执行异步操作,执行完成后到消息队列中排队。程序按照代码顺序执行完毕后,查询消息队列中是否有等待的消息。如果有,则按照次序从消息队列中把消息放到执行栈中执行。执行完毕后,再从消息队列中获取消息,再执行,不断重复。
主线程不断的重复获得消息、执行消息、再取消息、再执行。所以,这种机制被称为事件循环
![](https://img.haomeiwen.com/i13091615/be02b57d577ab66a.png)
事件循环的详细步骤如下:
1、所有同步任务都在主线程上执行,形成一个执行栈
2、主线程之外,还存在一个"消息队列"。只要异步操作执行完成,就到消息队列中排队
3、一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取消息队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行
4、主线程不断重复上面的第三步
图解JavaScript事件循环、执行栈、任务队列、宏任务、微任务:
![](https://img.haomeiwen.com/i13091615/9f221bcb65266078.png)
![](https://img.haomeiwen.com/i13091615/8ca4637d2721113e.png)
网友评论