编译器、解释器
1、在编译型语言的编译过程中,编译器首先会依次对源代码进行词法分析,语法分析,生成抽象语法树,然后是优化代码,最后再生成处理器能够理解的机器码,编译成功则会生成一个可执行文件,编译过程中发生错误,则会抛出异常,
2、解释型语言的解释过程中,解释器会对源代码进行词法分析、语法分析并生成抽象语法树,然后会基于抽象语法树生成字节码,最后根据字节码执行程序,输出结果。
V8执行一段js代码的流程
1、抽象语法树生成及执行上下文
将源代码转换成抽象语法树,并生成执行上下文。抽象语法树是一种数据结构,被广泛使用的代码转换器Babel大的工作原理就是先将ES6源码转换成AST,然后再将ES6语法的AST转换成ES5的AST,最后利用ES5的AST生成JavaScript源代码。ESLint同样也使用了AST。
AST的生成过程
1)分词,词法分析,将一行行的源码拆解成语法上不能再分的最小的字符或字符串。
2)解析,语法分析,将上一步拆解的数据,根据语法规则转换为AST。
2、生成字节码
字节码是介于AST和机器码之间的一种代码,但是与特定类型的机器码无关。字节码需要通过解释器将其转换为机器码后才能执行。
字节码相对于机器码占用的空间较小,可以减少系统的内存使用、
3、执行代码
在执行字节码的时候如果发现一段代码被重复执行多从,后台的编译器会把该段代码的字节码编译为高效的机器码,然后再次执行这段代码的时候,只需执行机器码即可,这样就大大提升了代码的执行效率。
消息队列、事件循环
1、消息队列中的任务称为宏任务,每个宏任务中都包含一个微任务队列,在执行宏任务的过程中,如果DOM有变化,那么就会将该变化添加到微任务列表中,这样就不会影响到宏任务的继续执行,等宏任务中的主要功能都直接完成之后,这时候渲染引擎会执行当前宏任务中的微任务。
第一版线程模型:确定好的任务,可以使用单线程按照顺序处理这些任务
第二版线程模型:在线程执行的过程中接收并处理新的任务,需要引入循环语句和事件系统
第三版线程模型:接收其他线程发来的任务,需要引入消息队列。
如果其他进程要发送任务给页面主进程,先通过IPC把任务发送给渲染进程的IO线程,IO线程再把任务发送给页面主线程。
XMLHttpRequest运行机制
1、创建XMLHttpRequest
对象
2、为xhr对象注册回调函数
XMLHttpRequest的回调函数主要有以下几种
- ontimeout:监控超时请求
- onerror:监控出错信息
- onreadystatechange:监控后台请求过程的状态,可以监控到http头加载完成的消息,http响应体消息以及数据加载完成的消息。
3、配置基础的请求消息
4、发起请求
宏任务和微任务
基于微任务的技术有MutationObserver
、Promise
以及以Promise
为基础开发的其他技术。
页面中的大部分任务是在主线程上执行的,这些任务包括渲染事件,用户交互事件,js脚本执行事件,网络请求完成,文件读写完成事件。为协调这些任务的执行,页面引入了消息队列和事件循环机制,渲染进程内部会维护多个消息队列,然后主线程不断的从这些任务队列中取出任务并执行任务,这些消息队列中的任务称为宏任务。
宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求不太符合。
微任务是一个需要一部执行的函数,执行的时机是在主函数执行结束之后,当前宏任务结束之前。
微任务产生的方式
- 使用
mutationObserver
监控某个DOM节点,然后通过js来修改这个节点,当DOM节点发生变化的时候就会产生DOM变化记录的微任务。 - 使用
promise
,当调用promise.resolve()
或者promise.reject()
的时候会产生微任务。
微任务的执行时机
在当前宏任务中的js快执行完成的时候,即js引擎准备推出全局执行上下文并清空调用栈 的时候,js引擎会检查全局执行上下文中的微任务队列,然后按照顺序执行队列中的微任务,如果在执行微任务的过程中产生了新的微任务,同样会将该微任务添加到微任务队列中,V8引擎一直循环执行微任务队列中的任务,直到队列为空。