javaScript代码,在浏览器中是如何被执行的?
2022-02-28 19:20 chengwei5211314 阅读(19) 评论(0) 编辑 收藏 举报当你在浏览器输入一个网址时,比如www.baidu.com,首先会dns解析,得到真实的ip地址,然后会向服务器发送请求,得到一个index.html ,解析这个文件,遇到link标签会下载css文件,遇到script标签会下载js文件。接下来就是渲染这些文件了。
认识浏览器内核
- 不同的浏览器有不同的内核组成
- Gecko:早期被Netscape和Mozilla Firefox浏览器浏览器使用;
- Trident: 微软开发,被IE4~IE11浏览器使用,但是Edge浏览器已经转向Blink;
- Webkit:苹果基于KHTML开发、开源的,用于Safari,Google Chrome之前也在使用;
- Blink: 是Webkit的一个分支,Google开发,目前应用于Google Chrome、Edge、Opera等;
- 事实上,我们常说的浏览器内核指的是浏览器的排版引擎:
- 排版引擎,也称为浏览器引擎、页面渲染引擎或样板引擎。
浏览器渲染过程
首先先看怎么对HTML和CSS进行操作的。
HTML首先会被浏览器内核中的HTML Parser解析,在这个过程中js也可能对DOM进行操作(紫色三角DOM),最终会构建成一颗DOM树,这里有个问题,就是谁来执行这些js代码?引出了js引擎。
css会被浏览器内核中的CSS Parser解析,形成css规则,css规则和DOM树结合形成一个渲染树,通过layout(布局)生成最终的渲染树。为什么要有layout呢?因为有的屏幕大小不一,那么元素所放到的位置也不一样。有了渲染树之后就可以绘制了,最终展现出来。
javaScript引擎
作用:javascript引擎帮助我们将js代码翻译成机器语言最终被cpu执行。
- 比较常见的js引擎有哪些呢?
- SpiderMonkey:第一款js引擎,由Brendan Eich开发(js作者)。
- Chakra:微软开发,由于IE浏览器。
- javascriptCore:webkit的js引擎,Apple公司开发。
- V8:Google开发的强大js引擎,也帮助Chrome从众多浏览器中脱颖而出。
浏览器内核和js引擎的关系
-
这里用webkit为列,webkit事实上由两部分组成的:
- webCore: 负责HTML的解析、布局、渲染等相关工作;
- javascriptCore:解析、执行js代码。
V8引擎的原理
v8是用C++编写的Google开源的高性能js引擎,v8可以独立运行,亦可以嵌入到任何c++程序中,所以node.js可以运行js代码。
1.js代码会经过parse解析,parse解析分为词法分析和语法分析。
如: const name = "why" 经过词法分析会生成tokens数组,里面存放的是一个个对象[{type: "keyword", value:'const'},{type:'identifier', value: 'name'}....]然后再经过语法分析之后生成AST抽象语法树,再经过ignition解释器解析成字节码,最后转为汇编语言再运行。
????为什么转成字节码?不直接生成机器码?
因为要考虑这个代码在不同环境中执行,生成字节码可以跨平台。
2.TurboFan是一个编译器,可以将字节码编译为CPU可以直接执行的机器码;
3.同时会收集TurboFan优化所需要的信息(比如函数参数的类型信息,有了类型才能进行真实的运算);
4.如果函数只调用一次,Ignition会执行解释执行ByteCode;
5.如果一个函数被多次调用,那么就会被标记为热点函数,那么就会经过TurboFan转换成优化的机器码,提高代码的执行性能;
6.但是,机器码实际上也会被还原为ByteCode,这是因为如果后续执行函数的过程中,类型发生了变化(比如sum函数原来执行的是number类型,后来执行变成了string类型),之前优化的机器码并不能正确的处理运算,就会逆向的转换成字节码;所以编写TS代码运行效率就会高一点。
V8执行的细节
- Blink内核将源码以流的方式交给v8引擎,v8引擎获取到源码并进行编码转换;
- Scanner会进行词法分析,词法分析会将代码转成tokens
- 接下来tokens会被转换成AST树,经过parser和Preparser
- parser就是直接将tokens转换成AST树结构;
- preParse称之为预解析,为什么需要预解析呢?
- 这是因为并不是所有的js代码,在一开始就会被执行,如果对所有的js代码都进行解析,会影响网页运行效率。
- 所以v8引擎就实现了延迟解析的方案,它的作用是将不必要的函数进行预解析,也就是只解析暂时需要的内容,而对函数的全量解析是在函数被调用时才会进行;
- 比如我们在一个函数outer内部定义了另外一个函数inner,那么inner函数就会进行预解析;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)