JavaScript 代码是怎么在浏览器里面运行的?
JavaScript 代码是怎么在浏览器里面运行的?下面让我们从浏览器内核和 JS 引擎两方面简单探索一下
浏览器内核
浏览器内核(Rendering Engine
),常见的叫法如:排版引擎、解释引擎、渲染引擎,现在流行称为浏览器内核。
浏览器渲染过程

HTML
首先会被浏览器内核中的HTML Parser
解析,最终会构建成一颗 DOM 树。CSS
会被浏览器内核中的CSS Parser
解析,形成 CSS 规则,CSS 规则和 DOM 树结合形成一个渲染树,通过 layout(布局)生成最终的渲染树。
为什么要有
layout
呢?因为要适配不同尺寸的屏幕。有了渲染树之后就可以绘制展现出来了。
常见的 js 引擎
SpiderMonkey:第一款 js 引擎,由 Brendan Eich 开发(js 作者)。
Chakra:微软开发,由于 IE 浏览器。
JavascriptCore:webkit 的 js 引擎,Apple 公司开发。
V8:Google 开发的强大 js 引擎,也帮助 Chrome 从众多浏览器中脱颖而出。
浏览器内核和 js 引擎的关系
这里用 webkit 为列,webkit 最重要的两部分:
WebCore
: 负责 HTML、CSS 的解析、布局、渲染等相关工作;JavascriptCore
:解析、执行 js 代码。
下面是 Chromium 的架构图

普通 JavaScript 引擎(笨重)
作用:javascript 引擎帮助我们将 js 代码编译成 CPU 认识的指令集,最终被 cpu 执行。
普通 JavaScript 引擎除了编译之外还要负责执行以及内存管理。 js 是解释形语言,由引擎直接读取源码,一边编译一边执行,这样效率相对较低,而编译形语言(如 c++)是把源码直接编译成可直接执行的代码执行效率更高。

随着技术的发展,对 JavaScript 性能的要求越来越高,V8 引擎就是在此背景下产生的,它产生的目的就是为了提高 javascript 执行的性能。
V8 引擎(轻量)
V8 引擎是一个 JavaScript 引擎实现,最初由一些语言方面专家设计,后被谷歌收购,随后谷歌对其进行了开源。
V8 使用 C++开发,在运行 JavaScript 之前,相比其它的 JavaScript 的引擎转换成字节码或解释执行,V8 将其编译成原生机器码(IA-32, x86-64, ARM, or MIPS CPUs),并且使用了如内联缓存(inline caching)等方法来提高性能。
将 javascript 代码转换成 AST
V8 引擎会先将 javascript 代码转换成 AST(抽象语法树),事实上所有的编程语言都会将源代码解析成抽象语法树(abstract syntax tree, AST)。
AST 是计算机科学中很早的一个概念,不是 V8 特有的(只是 V8 在转换过程中做了非常多的优化),更不是 javascript 特有的。
AST 的用途
AST 的作用也不仅仅是用来在 V8 的编译上,比如我们常用的 babel 插件将 es6->es5 、ts->js 、死区分析、Dead Code、编译压缩打包、css 预处理器、eslint 等等,这些功能的实现都离不开 AST。
AST 编译过程

V8 执行 js 的简易流程
浏览器内核将源码以流的方式交给 v8 引擎,v8 引擎获取到源码并进行编码转换
词法分析 Scanner,将代码转成 tokens
语法分析 Parser、Preparser,直接将 tokens 转换成 AST 树结构
字节码生成
parser 就是直接将 tokens 转换成 AST 树结构
preParse 称之为预解析,为什么需要预解析呢?
这是因为并不是所有的 js 代码一开始就会被执行,如果对所有的 js 代码都进行解析,会影响网页运行效率。所以 v8 引擎就实现了延迟解析的方案,将不必要的函数进行预解析,也就是只解析暂时需要的内容,而对函数的全量解析是在函数被调用时才会进行
比如我们在一个函数 outer 内部定义了另外一个函数 inner,那么 inner 函数就会进行预解析

下面看一下在线解析AST的示例👇

浏览器内核与 JS 引擎本篇就简单聊这么多,先浅浅的了解一下。关于 V8 的东西很多,也有很多非常绝妙的设计,更多 V8 相关的戳这里,一步步解锁吧!
我是 甜点 cc,个人网站(国外站点): https://blog.i-xiao.space/
回头看,轻舟已过万重山;向前看,前路漫漫亦灿灿。
公众号:【看见另一种可能】
版权声明: 本文为 InfoQ 作者【甜点cc】的原创文章。
原文链接:【http://xie.infoq.cn/article/304097471678197831de6e744】。未经作者许可,禁止转载。
评论