JS单线程
javascript是单线程的语言,也就是说,同一个时间只能做一件事。而这个单线程的特性,与它的用途有关,作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质
同步任务与异步任务
同步任务
在主线程上排队执行的任务;掐你给任务执行完毕,才能执行下一个任务
异步任务
不进入主线程,而进入“任务队列”的任务
任务运行机制
-
所有同步任务都在主线程上执行,形成一个“任务栈”
-
异步任务有了运行结果,就在“任务队列”中放置一个事件,等待执行
-
“执行栈”执行完毕,系统就将“任务队列”中的事件放入“执行栈”,开始执行
注意:栈:先进后出,队列:先进先出
宏任务与微任务
除了广义的同步任务和异步任务;还可以将异步任务细分为“宏任务”和“微任务”;对应的任务队列也可以细分为“宏任务队列”和“微任务队列”
宏任务
宏任务包括:
- script(整体代码)
- setTimeout
- setInterval
- I/O
- UI交互事件
- postMessage
- messageChannel
- setImmediate(node.js环境)
微任务
微任务包括:
-
Promise.then
-
Object.observe
-
MutationObser
-
process.nextTick(node.js环境)
注意:vue中的nextTick目前算作为微任务。实际上,nextTick在vue发展的不同版本中,针对各种渲染和dom事件问题进行了多次调整。宏/微任务,甚至两种并行。在最新版本 2.6.12 中稳定为 微任务
任务运行机制
- 解析代码,遇到微任务,就添加到“微任务队列”中,遇到宏任务,就添加到“宏任务队列”中
- 依次将微任务队列中的任务放入执行栈,执行完毕
- 微任务队列全部执行完毕后,依次将“宏任务队列”中的第一个宏任务放入执行栈
- 重复第一步,直到所有宏任务执行完毕
事件循环执行顺序
- 首先执行执行栈里的任务
- 执行栈情况后,检查微任务队列,依次将微任务队列中的任务放入执行栈,执行完毕
- 微任务队列全部执行完毕后,依次将“宏任务队列”中的第一个宏任务放入执行栈
- 重复第一步,直到所有宏任务执行完毕
流程图如下: