第一天
浏览器下载渲染
请求域名以后,会返回一个index.html,然后开始碰到css了就下载css,碰到js就下载对应的js,然后渲染网页(好像大概是这样)
浏览器内核就是用来排版的?解析

v8引擎如何执行js代码
高级语言写的代码最终得让cpu执行的,cpu只认识自己的指令集
js引擎:js代码 => cpu指令集
常见的JavaScript引擎
SpiderMonkey:第一款js引擎,由js作者(Brendan Eich)开发
Chakra:微软开发,用于IE浏览器
JavaScriptCore:webkit的js引擎,apple开发
V8:chrome的js引擎。Google开发
...
浏览器内核 和 js引擎 的关系
以webkit为例:由两部分组成
- WebCoer:负责HTML解析、布局、渲染等等
- JavaScriptCoer:解析、执行JavaScript代码
v8引擎的原理
v8引擎是c++编写的开源的
用于chrome和node.js
解析
js源码 => v8引擎 => cpu
第一步解析(parse):词法分析和语法分析
词法分析:就是一个词一个词的分析,看图
然后再语法分析,生成AST抽象语法树
这里有个网站可以看代码的ast树
新知识:babel里用了抽象语法树,babel是干嘛的,好像可以把ts代码转为js?ts到ast语法树,再到新的ast再到js代码,还有vue template
还可以把es6转为es5
通过ignation(一个库)把ast转为字节码(字节码是什么?)
字节码是什么?有撒用
为什么不直接把源码翻译成机器码0101一部搞定呢?
因为你写的代码,他不确定最终会运行在什么架构的cpu上,mac电脑windows电脑等等
这时候那个ignation就不知道该转成哪个cpu的了
但是字节码(bytecode)是跨平台的,是v8引擎规定好的字节码。
从字节码再转到机器码(针对不同的cpu),就是v8引擎的工作(将字节码转为汇编语言,再去执行cpu指令)
v8引擎的优化好牛啊
先讲场景:比如写了一个循环函数,这时候每次循环都转成字节码 => 汇编 => 机器码,就会很慢
这时候它就会检测,如果你是个hot热函数,运行频繁,
那就直接现场把你转为0101直接发给cpu执行,就不用上面那些步骤了(好像是这样子)
还有一个库叫TurboFan,从ignation里检测hot函数,然后变成机器码。
但是,函数很复杂的,一个函数可能既hot又cold。hot是什么意思呢,就是说举个例子写了个两个数字相加的构造函数,然后调用传进去两个数字,那么优化的机器码就只负责做两个数字的加法就可以了,但是如果有一条命令传进去两个字符串呢?就得拼接字符串了,那这个就不可以用上面的优化的只做数字加法的机器码执行了,这时候就得反向优化,传回去变成字节码走上面那条路。
❓疑问: 其实还是不很清楚,有点懵,只是知道有这么个流程,但是不知道具体怎么搞的,要是像ast树那样有个网站给看看过程就好了
v8引擎源码 ?飘了
100w行c++!!!GitHub搜索v8就是了

预解析 preparser

js代码执行过程
假设你写了一段代码
var name = 'why'
var num1 = '20'
var num2 = '30'
var result = num1 + num2
按照上面的图片,先解析,再转为字节码,再有结果
具体过程
- 首先你得放在有v8引擎的环境
- 然后v8还没看你的代码呢,就先来建一个全局对象: var GlobalObject = {}
- 这个GlobalObject里有啥呢?有当前环境(不管是浏览器还是node)里已经有的一些全局对象,就是string,Date,Number,math,array,setTimeout,console.log,window:this等等一堆,就是你写代码的时候会给你提示的那些,哪里来的,就是这里的全局对象里的

- 这里的window指向这个GlobalObject
- 同时,GlobalObject还会放你的全局变量,看下面👇
var GlobalObject = {
String: "类",
Date: "类",
setTimeout:"类",
window: globalObject,
name: undefined,
num1: undefined,
num2: undefined,
result: undefined,
}
- 因为这是解析,代码没有执行,所以没有赋值,所以变量名还是默认值undefined。
- 然后为了执行代码,v8内部有一个执行上下文栈(就是函数调用栈)
- 但是,这个栈一般是放函数的,全局代码里有很多不是函数的代码,比如我上面写的。那些怎么放进去函数调用栈呢?
- 这时候全局上下文(global execution context)就出现了,把这个GEC当作函数一样放进函数调用栈
- 那么这个全局执行上下文GEC里面有什么?
- 里面一个东西叫VO(variable object变量对象),这个VO在这里指向了GO(就是GlobalObject)。
- 这个VO也有作用域链,也有this的
- var name = "why"这条代码开始执行
- 往VO找到GO那边,在GO里面找到name这个变量,把undefined改成why
- 如果这段代码,我在第二行打印num1,那么就会输出undefined,因为num1变量已经在go里面了,默认值是undefined,所以可以打印出来,虽然声明赋值代码还在下面呢。
- 这就是作用域提升

总结
总结就是,收获很多,越往后越硬核,coderwhy yyds!