浏览器事件循环与vue nextTicket的实现

2020-06-13 10:30:57易采站长站整理

同步:就是在执行栈中(主线程)执行的代码
异步:就是在异步队列(macroTask、microTask)中的代码

简单理解区别就是:异步是需要延迟执行的代码

线程和进程

进程:进程是应用程序的执行实例,每一个进程都是由私有的虚拟地址空间、代码、数据和其它系统资源所组成;进程在运行过程中能够申请创建和使用系统资源(如独立的内存区域等),这些资源也会随着进程的终止而被销毁
线程:线程则是进程内的一个独立执行单元,在不同的线程之间是可以共享进程资源的,是进程内可以调度的实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程。

简单讲,一个进程可由多个线程构成,线程是进程的组成部分。

js是单线程的,但浏览器并不是,它是一般是多进程的。

以chrome为例: 一个页签就是一个独立的进程。而javascript的执行是其中的一个线程,里面还包含了很多其他线程,如:

GUI渲染线程
http请求线程
定时器触发线程
事件触发线程
图片等资源的加载线程。

事件循环

ok,常识性内容回顾完,我们开始切入正题。

microTask 和 macroTask

常见的macroTask有:setTimeout、setInterval、setImmediate、i/o操作、ui渲染、MessageChannel、postMessage

常见的microTask有:process.nextTick、Promise、Object.observe(已废弃)、MutationObserver(html5新特性)

用线程的理论理解队列:

macroTask由事件触发线程维护
microTask通常由js引擎自己维护

一个完整的事件循环(Event loop)过程解析

初始状态:调用栈(主线程)、microTask队列、macroTask队列,macroTask里只有一个待执行的script脚本(如:入口文件)
将这个script推入调用栈,同步执行代码。在这过程中,会调用一些接口或者触发一些事件,可产生新的marcoTask与microTask。它们分别会被推入各自的任务队列。同时该script脚本会被从macroTask中移除,在调用栈执行的过程就称之为一个tick。
调用栈代码执行完成后,需要处理的是microTask中的任务。将里面的任务依次推入调用栈执行。
待microTask 所有 的任务都执行完成后,再去macroTask中获取优先级最高的任务推入调用栈。
执行渲染操作,更新界面
查看是否有web worker,如果有,则对其进行处理。

(上述过程循环往复,直到两个队列都清空)

注意:处理microTask中的任务时,是执行完所有的任务。而处理macroTask的任务时是一个一个执行。