专栏首页前端菜鸟变老鸟Webkit底层原理(3)--HTML解释器

Webkit底层原理(3)--HTML解释器

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/caomage/article/details/102072801

1. 解释过程

HTML解释器的工作就是将从网络或本地磁盘获取的HTML网页和资源从字节流解释成DOM树结构。如下图:

图中将这一过程描述得很清晰:首先是字节流,经过解码之后是字符流,然后通过词法分析器会被解释成词语(Tokens),之后经过语法分析器构建成节点,最后这些节点被组成一颗DOM树。

2. 词法分析

在进行词法分析之前,解释器首先要做的就是检查该网页内容使用的编码格式,以便后面使用合适的解码器。如果解释器在HTML网页中找到了设置的编码格式,Webkit会使用相应的解码器将字节流转换成特定格式的字符串。如果没有特殊的格式,词法分析器HTMLTokenizer可以直接进行词法分析。 词法分析的工作都是由HTMLTokenier来完成,简单来说,它就是一个状态机–输入的是字符串,输出的是一个个的词语。因为字节流可能是分段的,所以输入的字符串可能也是分段的,但是这对词法分析器来说没什么特别之处,它会自己维护内部的状态信息。 词法分析器的主要接口是nextToken函数,调用者只需要将字符串传入,然后就会得到一个词语,并对传入的字符串设置相应的信息,表示当前处理完的位置,如此循环。如果词法分析器遇到错误,则报告状态错误码。 而对于词语的类别,Webkit是定义了很少,HTMLToken定义了6种词语类别,包括:DOCTYPE、StartTag、EndTag、Comment、Character和EndOfFile。这里不涉及HTML的标签类型等信息,那是后面语法分析的工作。

3. XSSAuditor验证词语

XSSAuditor是一个重要的类,是面试中会经常遇到的一个问题。 当词语生成之后,Webkit需要使用XSSAuditor来验证词语流(Token Stream)。XSS指的是Cross Site Security,主要是针对安全方面的考虑。 根据XSS的安全机制,对于解析出来的这些词语,可能会阻碍某些内容的进一步执行,所以XSSAuditor主要负责过滤这些被阻止的内容,只有通过的词语词啊会作后面的处理。详细的内容后面的文章我会再做介绍。

4. 词语到节点,从节点到DOM树

经过词法分析器解释之后的词语随之被XSSAuditor过滤并且在没有被阻止之后,将被Webkit用来构建DOM节点。主要是利用之前分成的6种词语,生成对应的节点。 因为HTML文档的Tag标签是有开始和结束标记的,所以构建这一过程可以使用栈结构来帮忙。其中,使用一个栈来保存元素节点,其中的元素节点是当前有开始标记但是还没有结束标记的元素节点。想象一下HTML文档的特点,例如:

<body>
  <div>
  	<span></span>
  </div>
</body>

当解释到span标签元素的开始标记时,栈中的元素就是body、div和span,当遇到span的结束标记时,span出栈,span时div的子女;当遇到div的结束标记时,div出栈,表明div和它的子女都已经处理完毕,以此类推。

5. 线程化的解释器

顾名思义,线程化的解释器就是利用单独的线程来解释HTML文档。因为在Webkit中,网络资源的字节流自IO线程传递给渲染线程之后,后面的解释、布局和渲染等工作基本上都是工作在该线程,也就是渲染线程完成的。因为DOM树只能在渲染线程上创建和访问,这就是说构建DOM树的过程只能在渲染线程中进行。但是,从字符串到词语这个阶段可交给单独的线程来做,Chromium就是这个思想。

6. JavaScript的执行

在HTML解释器工作过程中,可能会有JavaScript代码需要执行,它发生在将字符串解释成词语之后、创建各种节点的时候。这也是为什么全局执行的JavaScript代码不能访问DOM树的原因–因为DOM树还没有被创建完成。 Webkit将DOM树创建过程中需要执行的JavaScript代码交给HTMLScriptRunner类来执行。工作方式很简单,就是利用JavaScript引擎来执行Node节点中包含的代码。 因为JavaScript代码可能会调用例如document。write()来修改文档结构,所以JavaScript代码的执行会阻塞后面节点的创建,同时当然也会阻塞后面资源的下载,这时候Webkit对需要什么资源一无所知,这导致了资源不能够并发的下载这种性能问题。所以使用JavaScript的时候有以下两点优化建议:

  1. script标签加上async属性,表明这是一个可以异步执行的代码;
  2. script标签放到body元素的最后,也就是</body>之前。

此外,针对资源不能够并发的下载这种性能问题,Webkit使用预扫描和预加载机制来解决。具体的做法是:当遇到需要执行JavaScript代码的时候,Webkit先暂停当前JavaScript代码的执行,使用预扫描器来扫描后面的词语,如果发现需要使用其他资源,就会使用预加载器发送请求获取资源,在这之后,才开始执行JavaScript代码。预扫描器本身并不难创建节点,也不会创建DOM树,所以速度比较快。就是如此,还是建议使用上面的两点优化建议。

当DOM树构建完之后,Webkit触发DOMContentLoaded事件,注册在该事件上的JavaScript函数会被调用。当所有资源都被加载完之后,Webkit会触发onload事件。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Webkit底层原理(4)--DOM事件机制和Shadow DOM

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    从入门到进错门
  • ES6(二):Promise

    ES6之前解决异步编程只能使用回调函数或事件,ES6中加入了 Promise,使得异步编程更加简洁直观和合理

    从入门到进错门
  • js实现截图并保存图片(html转canvas、canvas转image)

    从入门到进错门
  • 一个简单登录页面就能看出你的设计功底,不信?|来试试

    一个合格的注册登录页面,应该是具有清晰的操作流程,良好的交互细节和美观的视觉设计。 清晰的操作流程 APP的注册登录有四种情况: 不需要注册登录 常见于系统自带...

    BestSDK
  • MATLAB HDL Coder开发环境设置

    MATALB HDL Coder+Simulink对于视觉开发人员来说比Vivado HLS更加友好。但是Mathworks的example一如既往的杂乱无章。...

    FPGA开源工作室
  • 产品设计进阶思维:怎样进行业务的抽象建模

    抽象建模是产品设计中的一个很重要思路,它能帮助我们将一些看似没有任何规律的业务进行一个标准化。

    一个会写诗的程序员
  • Web-第六天 MySQL回顾学习

    数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户可以通过sql语句对数据库中的数据进行增加,修改,删除及查询操作

    奋斗蒙
  • 数据迁移-MGR、PXC与Replication Filter

    针对两种方案,有非常多的迁移手段,而迁移之前数据是否持续同步,或者迁移过程dump+load等类似方式,会决定了业务的影响时间。

    [3306 Pai ] 社区
  • 基于Elastic Search的推荐系统“召回”策略

    当我们打开一个资讯APP刷新闻时,有没有想过,系统是如何迅速推送给我们想看的内容?资讯APP背后有一个巨大的内容池,系统是如何判断要不要将某条资讯推送给我们的呢...

    第四范式-先荐
  • AraBERT:基于变压器的阿拉伯语理解模型(CS.CL)

    与英语相比,阿拉伯语是一种形态丰富且复杂的语言,具有相对较少的资源和较少探索的语法。鉴于这些限制,事实证明,诸如情感分析(SA),命名实体识别(NER)和问答(...

    蔡小雪7100294

扫码关注云+社区

领取腾讯云代金券