image.png

前言

​ 感觉自己做前端这行业,应该要接近两年了吧。在这两年或者三年(大四的时候也在接触)中,天天跟着 JavaScript 语言打交道。从大学开始学习的 JavaScript语法JQuery库, 然后到为了找工作学习 Vue2, 却找了一个使用 React 的公司,以及在平时学习最新出来的 Vue3。上面一系列的过程,全都是在跟 JavaScript 打交道。 所谓的打交道,就是在使用过程中,不停的使用基础语法进行开发,就没有然后呢......

​ 也许,如果没有想着要提升自己的实力水平,这样就行了,完成就是目标。但是大多数人,应该都还是想提升自己的实力的(其中也包括我吧)。所以,使用 JavaScript 编程,不仅需要对基本语法进行掌握,也要对其中的一些原理进行了解吧。

因为了解真相,你才能获得真知的自由。

​ 在平时准备面试的时候,总会看到一些关键词 浏览器内核JavaScript引擎。那么这两个到底是干什么的呢?在其中起到了什么作用呢?

​ 我跟随着前端大神coderwhy老师的脚步,了解真相,记录此篇。(此篇基本上是纯理论,但是如果懂了,获益良多)

认识 JavaScript

JavaScript 是一门编程语法,简单的来说,是一门高级的编程语言。为啥说是高级的编程语言呢?

那么有高级编程语法,那么就有低级编程语法。

  • 机器语言(低级):所谓的机器指令(二进制编码 01010011111000)
  • 高级语法:C、C++、Java、JavaScript等

针对计算机而言,根本就不认识所谓的高级语言,写的啥完全看不懂。想要被计算机所认识,那么所谓的高级语言就需要转换成机器指令。所以,JS代码就会被转化成机器语言,被计算机的CPU所认识。

大致就是这么一回事。

这个解析的过程就是 JS引擎,下面会更加详细的说明。

浏览器的工作原理

有没有深入的思考过: JavaScript代码是如何在浏览器中被执行的?

比如: 浏览器中输入 http://www.baidu.com,其中做了什么?

步骤解析:

  1. 输入 http://www.baidu.com, 就会被浏览器解析成一个ip地址(假设: 111:222:333:444),根据这个ip地址,就会找到一台服务器,服务器就会返回一个 index.html 文件,用来解析。(注意: 这里并不是把所有的静态资源到返回了,在框架时代,就应该是所谓的分包操作吧。打包成多个 chunk.js, 用到时再加载)。
  2. 在解析 index.html 过程中,如果遇到 link 标签,就会去服务器中下载对应的 css 文件;如果遇到了 script 标签,就回去服务器中下载对应的 js 文件。

在上面的过程中,拿到 index.html 文件,被解析,是被谁所解析的呢?

答案是: 浏览器内核

认识浏览器内核

在准备面试题的时候,或多或少都会了解到浏览器的内核。

不同的浏览器有不同的内核组成。

常见的几种内核:

  • Gecko: 早期被 Netscape 和 Mozilla Firefox浏览器使用。
  • Trident: 微软开发,被IE4~IE11浏览器使用,但是Edge浏览器已经转向Blink。
  • Webkit: 苹果基于KHTML开发,开源的,用于Safari,Google Chrome之前也在使用。
  • Blink: 是Webkit的一个分支,Google开发,目前应用于Chrome、Edge,Opera等。

事实上,浏览器的内核指的是浏览器的排版引擎

排版引擎:也称为浏览器引擎,页面渲染引擎。从字面量的大致意思: 浏览器内核就是处理页面布局的。

浏览器渲染流程

根据上面的图解,可以得出以下信息:

  • HTML 经过 HTML Parser 生成解析 DOMTree,Style 经过 CSS Parser解析生成 StyleRules。
  • DOMTree 和 StyleRules 结合,生成渲染树(RenderTree)
  • 执行 layout 过程,确定每个节点在屏幕上的确切坐标。
  • 渲染树 绘制(Painting),然后展示在屏幕上。

注意:上面的步骤并不是严格顺序执行的。浏览器引擎会以最快的速度展示内容。简单的来说,就是一边解析HTML一边构建渲染树,构建一部分,就会把以后的元素渲染出来。如果样式没有加载出来,就会以浏览器默认的样式展示。

正是由于浏览器引擎的尽快展示内容,就会造成样式还没加载就展示的问题。这就是经常发生的FOCU(flash of unstyled content)或则 白屏问题。

CSS加载不会阻塞DOM树的解析

通过上面的图解可以看出,HTML解析和CSS解析,是并行的。所以CSS加载不会阻塞DOM树的解析

CSS加载会阻塞DOM树的渲染

渲染树(RenderTree)是 DOMTree 和 StyleRules 的结合。所以,就算DOMTree加载完成,也要等到CSS加载完成并解析完成,才能生成渲染树。

JS执行会阻塞DOM树的解析

从渲染图可以知道 HTML 解析成 DOMTree, 如果遇到 JavaScript 代码, 就会停止解析HTML,就会把控制权交给 JS引擎, 去执行 JavaScript 代码。当 JavaScript 执行完成后,浏览器再从中断的地方继续解析生成DOM。

这也是建议将 script 标签放在 body 标签底部的原因。

特殊情况:

在上面也说过了,CSS加载不会阻塞DOM树的解析。但是呢?如果在解析DOM的时候,里面加入script标签,引入了JavaScript代码(js是万能的,也可以修改DOM,也可以修改样式)。如果JavaScript代码,需要修改样式,那么就需要等待CSS加载完毕,才能操作CSS。所以在这种特殊的情况下,css加载也是会阻塞DOM的解析

优化渲染过程

  • 使用内联的JS、CSS,减少JS、CSS文件的下载。
  • webpack等工具对JS、CSS文件压缩,减少文件的大小。
  • 使用 async 或者 defer。
  • 使用CDN。

认识 JavaScript 引擎

在上面的浏览器渲染过程中,在解析DOM的时候,会遇到 JavaScript 代码,那么这下的控制权就会交给 JS 引擎来执行JavaScript代码。

为什么需要JavaScript引擎?

前面说过,JavaScript是一门高级的编程语言,想要被计算机CPU认识,就需要转化成机器指令。JavaScript引擎就是来做这一件事的,把JS代码转化机器指令

常见的JavaScript引擎

  • SpiderMonkey: 第一款JavaScript引擎,由Brendan Eich开始(也就是JavaScript的作者)。
  • Chakra: 微软开发,用于IE浏览器。
  • JavaScriptCore: Webkit 中的 JavaScript 引擎, Apple公司开发。
  • V8: Google 开发的强大 JavaScript 引擎。

浏览器内核和JavaScript引擎的关系

这里以 Webkit 内核为例:

Webkit事实上有两部分组成:

  • WebCore: 负责HTML解析、布局、渲染等等事情。
  • JavaScriptCore: 解析、执行 JavaScript 代码。
跟微信小程序架构很相似。

可以看出关系: JavaScript引擎是浏览器内核组成的一部分。

认识 V8引擎(了解)

定义

V8引擎是C++编写的Google开源高性能的 JavaScript 引擎,用于Chrome和Node.js等。

运行流程

JS引擎就是把JavaScript代码转化成机器指令,在计算机的CPU中运行。

Parse模块拿到 JavaScript 源码会进行解析生成AST树,AST树简单来说,就是一个固定格式对象,经过一系列的处理,变成字节码(bytecode),最后变成机器指令。

AST树应该不陌生吧。在现在的框架时代,react的jsx解析,vue的template解析,还是ts解析,babel解析等等操作,都是离不开生成AST树进行转换的。

测试AST树结构的地址: https://astexplorer.net

V8执行的细节

Parse的V8官网地址: https://v8.dev/blog/scanner

JavaScript源码如何被解析(Parse)的呢?

  • Blink将源码交给v8, Stream获取源码并进行编码转换。
  • Scanner会进行词法分析,词法分析会将代码转化成tokens。

    const name = 'copyer'
    // 解析成tokens
    tokens = [
        {type: 'VariableDeclaration', value: 'const'}, 
        {type: 'Identifier', value: 'name'},
        {type: 'Literal', value: 'copyer'}
    ]

    大致的形式就是这样的。

  • 然后就是tokens转化为AST树,会经过两个步骤Parser和PreParser.

    • Parser就是直接将tokens转成AST树。
    • PreParser称为预解析,处理一些最开始不需要执行的代码,不需要转成AST树,只需要在调用的时候,才解析。目的就是为了性能优化。
  • 最后就是根据AST生成bytecode,转化成机器指令。

总的来说,上面的一系列步骤,只需要有点印象即可。但是需要了解一个步骤:

Parse模块解析,这里会进行词法分析语法分析

在开发过程中,变量的提升就是在语法分析这一步完成的。

总结

​ 该篇文章完全就是纯理论,就是为了以后在JavaScript方向发展,有一个更好的认识而已。也许,对于我来说,今天学习了,感觉懵懵懂懂的知道了(只有经常使用,熟悉了,可能才不会忘记)。但是过几天之后,也许就可能忘记了。这篇就是为了帮助我以后更好的回忆一下,我曾经了解过,忘记了,我可以再次熟悉。

​ 虽然是纯理论,但是不可否认,这些理论的重要性,可以更好的理解我们在开发中的一些现象和问题。同时也是菜鸟向JavaScript学习的进阶的方向。


copyer
4 声望0 粉丝

成长中的码农