JavaScript代码是怎么在浏览器里面运行的?下面简单探索一下
浏览器内核
浏览器内核(Rendering Engine
),常见的叫法如:排版引擎、解释引擎、渲染引擎,现在流行称为浏览器内核。
浏览器 | 内核 | 说明 |
---|---|---|
IE | Trident | IE、猎豹安全、360极速浏览器、百度浏览器 |
FireFox | Gecko | 可惜这几年已经没落了,打开速度慢、升级频繁、猪一样的队友flash、神一样的对手chrome。 |
Safari | Webkit | 从Safari推出之时起,它的渲染引擎就是Webkit,一提到 webkit,首先想到的便是 chrome,可以说,chrome 将 Webkit内核 深入人心,殊不知,Webkit 的鼻祖其实是 Safari。 |
Chrome | Chromium/Blink | 在 Chromium 项目中研发 Blink 渲染引擎(即浏览器核心),内置于 Chrome 浏览器之中。Blink 其实是 WebKit 的分支。大部分国产浏览器最新版都采用Blink内核。二次开发 |
Opera | Blink |
浏览器渲染过程
-
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的示例