AST语法树
AST 简介
在计算机科学中, 抽象语法树(Abstract Syntax Tree, AST)或者简称语法树(Syntax Tree)是源代码语法解构的一种抽象表现, 它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构. – 维基百科
而在 JavaScript 中我们通过 JavaScript Parser 把代码转化为一颗抽象语法树(AST),这颗树定义了代码的结构,通过操纵这颗树,我们可以精准的定位到声明语句、赋值语句、运算语句等等,实现对代码的分析、优化、变更等操作. 然后浏览器会把 js 源码通过解析器转为抽象语法树,再进一步转化为字节码或直接生成机器码.
AST 生成过程
总的来说一段源代码在执行之前会经历如下过程:
- 分词 / 词法分析: 将一个语句中的关键词进行提取, 例如
let a = 3;
, 分词提取之后得到let
,a
,=
,3
,;
- 解析 / 语法分析: 在对上面已经被拆分提取过的关键词进行分析之后建立一课语法树(
AST
), 效果可参见下面 - 底层代码生成: 得到语法树之后执行引擎(例如 chrome 的 v8引擎)会对这颗树进行一定的优化分析, 然后生成更底层的代码或者机器指令交由机器执行
无图不真相, 我们借助一个在线的可视化工具或者esprima来具体看一下过程, 对于如下代码进行生成 AST 树
- 源码:
var a = 42;
var b = 5;
function (d) {
return a + d;
}
var c = addA(2) + b;
- 词法分析结果
Keyword(var) Identifier(a) Punctuator(=) Numeric(42) Punctuator(;) Keyword(var) Identifier(b) Punctuator(=)
Numeric(5) Punctuator(;) Keyword(function) Identifier(addA) Punctuator(() Identifier(d) Punctuator())
Punctuator({)Keyword(return) Identifier(a) Punctuator(+) Identifier(d)Punctuator(;)
Punctuator(}) Keyword(var) Identifier(c) Punctuator(=) Identifier(addA)
Punctuator(()Numeric(2) Punctuator()) Punctuator(+) Identifier(b) Punctuator(;)
- 生成 AST 树
{
"type": "Program",
"body": [{
"type": "VariableDeclaration",
"declarations": [{
"type": "VariableDeclarator",
"id": {
"type": "Identifier",
"name": "a"
},
"init": {
"type": "Literal",
"value": 42,
"raw": "42"
}
}],
"kind": "var"
}, {
"type": "VariableDeclaration",
"declarations": [{
"type": "VariableDeclarator",
"id": {
"type": "Identifier",
"name": "b"
},
"init": {
"type": "Literal",
"value": 5,
"raw": "5"
}
}],
"kind": "var"
}, {
"type": "FunctionDeclaration",
"id": {
"type": "Identifier",
"name": "addA"
},
"params": [{
"type": "Identifier",
"name": "d"
}],
"body": {
"type": "BlockStatement",
"body": [{
"type": "ReturnStatement",
"argument": {
"type": "BinaryExpression",
"operator": "+",
"left": {
"type": "Identifier",
"name": "a"
},
"right": {
"type": "Identifier",
"name": "d"
}
}
}]
},
"generator": false,
"expression": false,
"async": false
}, {
"type": "VariableDeclaration",
"declarations": [{
"type": "VariableDeclarator",
"id": {
"type": "Identifier",
"name": "c"
},
"init": {
"type": "BinaryExpression",
"operator": "+",
"left": {
"type": "CallExpression",
"callee": {
"type": "Identifier",
"name": "addA"
},
"arguments": [{
"type": "Literal",
"value": 2,
"raw": "2"
}]
},
"right": {
"type": "Identifier",
"name": "b"
}
}
}],
"kind": "var"
}],
"sourceType": "script"
}
AST的作用
除了帮助执行引擎去生成底层的代码, AST 在我们常见的代码检查工具或者 webpack 中都可以用来作为代码分析的依据, 通过遍历 AST 树, 找出其中的隐藏问题, 或者提出优化的建议, 又或者是代码高亮或者代码压缩都是在分析这颗树的基础上进行的
浏览器渲染过程
首先我们看一下浏览器的深层结构:
- 用户界面-包括地址栏, 返回按钮等 UI 组件, 除了主窗口
- 浏览器引擎-用来查询和操作渲染引擎的接口
- 渲染引擎-负责渲染请求的内容. 比如, 如果请求的资源是html, 那么渲染引擎负责解析 html 和 css, 然后把解析结果渲染到页面中
- js 引擎-用来解析执行 JavaScript 代码
- 网络连接-用于处理网络请求, 如 http 请求. 这一部分是跨平台的
- UI 后台-用于渲染基础组件, 比如多选框和窗口等, 它暴露了一个不是特定平台的通用接口, 在底层调用了操作系统的用户接口
- 数据存储-这是一个持久层. 浏览器在硬盘中存储各式数据, 比如 cookie , localStorage 等
各个组件的关系如下:
我们需要注意的是, js 引擎是单线程的, 但是浏览器是多线程的, 比如浏览器会同时开启js 引擎线程, 界面渲染线程, 事件触发线程, http 请求线程
HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
接下来我们着重看一下渲染引擎所做的工作:
总的过程是: 解析HTML并构建DOM树 => 构建render树 => render树布局 => render树绘制
浏览器引擎开始解析 html, 并把标签转为内容树中的 dom 节点, 同时它也开始解析 css, 外链的 css 以及文件内的 css, 所有这些样式数据以及 html 中的可见性指令都用来构建另外一棵树, – render 树
我们以Safari 和 chrome 使用的Webkit 引擎渲染过程如下:
以上是 AST语法树 的全部内容, 来源链接: utcz.com/a/11116.html