zoukankan      html  css  js  c++  java
  • A machine

      可能就像遇到新奇器具那样,外表精致却总想拆开看看,一探究竟,不然心痒痒的,准确说,心里憋得慌,还是拆开浏览器玩玩先~

      浏览器可以分两部分:shell+内核,现在市面有挺多浏览器在结合多核的基础上使用自身shell,即浏览器外壳,包括地址栏,菜单,各种按钮控件,说白了就是用户界面,对用户友好~卸下这层外壳,剩下的就是代码“组件”了。

      浏览器引擎用于用户界面与渲染引擎之间的通讯,渲染引擎则负责将服务器传送过来的html与css进行解析并绘制呈现于屏幕;js解释器用于解析与执行js代码;网络用于网络传输,其接口与平台无关,由平台提供底层实现;通过用户界面后端绘制基本控件;数据存储层用于数据保存,例如Cookie,HTML5的web database等。

      对于页面的呈现,其实就像电视机,通过天线接收电视台发射的电视信号(html,css等),电子线路分离出视频信号和音频信号(解码),分别通过荧光屏和喇叭还原(渲染)为图像和声音(呈现)。拆过机体看过内部的人都会知道内部其实是各种各类的元器件分组成不同功能的功能块,对于不同信号源按序加载并流入不同组件进行解译,这过程各部件各司其职的同时也相互交互,协同工作。

      对于浏览器也一样,无非就是程序员通过代码结合相应规则去控制屏幕像素点,告诉计算机,该怎么去表现,在表现的最底层其实就是计算机硬件,各种芯片,它们使用的是机器语言,虽说都是0,1码,但不同硬件配备会有不同的方言,而浏览器在这其中充当了翻译者,当然,由于浏览器大战,各浏览器少不了牛脾气,解决bug,改进代码质量需要我们去了解浏览器,站在浏览器上去思考。

      对于文件代码的解析包括词法分析与语法分析,即识别标记并匹配语法规则。


    HTML解释器

      对于HTML的解析,由于它具有与上下文相关的语法规则,所以它不适合单纯的自上而下或自下而上的解析法,而是由DTD定义,包括所有允许使用的元素,属性与层次结构,具有一定的容错性。这个解析过程包括两部分:标记提取,树构建。标记提取就是扫描过程中通过识别“<”,“>”,“/”来判断是否为标签,并记录标签名,传入树构造器参加树模型的构建,后进行下一标记识别。

    标记识别过程

      元素传入树构造器后,按照DTD定义的规范创建相应DOM元素来构建树。这些DOM添加到树的同时添加至开放元素堆栈,用于纠正嵌套,处理未关闭的标记。

    构造器

    树的构建


    CSS解释器

      CSS是一种与上下文无关的语法,其词法是针对各个标记用正则表达式定义,而词法则是采用BNF格式描述。WebKit使用的是Bison生成的自下而上的移位归约解析器,Firefox使用的是人工编写的自上而下的解析器。应用样式表不会改变DOM树,但当脚本请求未加载并解析的样式信息时会出错。WebKit仅当脚本尝试访问未加载并解析的样式信息时禁用脚本,而Firefox在样式表解析与加载时会禁用脚本。

      此时构建的是呈现树,DOM树构建期间同时解析CSS,类似于记录原料(可视化对象)信息的过程,包含各选择器宽高,位置,可视化属性等信息,之后附加或映射到DOM树上。解析器从右到左识别标记并选择一条DOM树路径向上遍历节点树进行样式匹配,因此我们设置CSS样式的匹配层越少,匹配条件越精确,同时去除不必要节点,简化DOM树结构,能大大减轻减轻解析器的工作压力。

      CSS样式计算来源包括浏览器默认属性,用户样式表,网页制作者样式表。一个选择器的属性值来自于继承值,默认值与设置值的综合。对于BFC,则去除继承属性再综合,对于同BFC下的元素,则按各属性权值去层叠以确定表现形式,由于是向上遍历,所以在父级基础上去计算属性值,即父级已经记录了该路径位于元素上方的特性值。因为整个结构共享,可以减少计算与节约内存。CSS解析后存储在哈希表中,以便查询。


    JavaScript解释器

      它让我想到了遥控器,以事件为驱动,用户按下相应按钮时,按键矩阵电路会送出相应编码的电平信息,通过各种信号处理后以红外的形式完成与电视机体的交互,机体通过解码电路,提取相关信息,做出相应反应,这样便实现了相应控制。

      同理,若文档中有JS文件,则按序加载,并启动JS引擎,按序解码执行。其工作方式有:传统的遍历语法树;中间码(字节码);JIT编译

      JS可以控制样式与节点,会影响DOM树与呈现树的结构,在解析期间往往会与HTML,CSS解析器有所交互。在预解析期间会配置相关执行环境(变量,函数声明提升),此时其他线程会解析文档其他部分,找出需要网络加载的其他资源,并行加载。解析结束后触发“onload”。

      传统的遍历语法树的方式先构建各语句语法树,执行每个语句都需要遍历相应语法树,可想而知当遇到for语句时就需要多次后序遍历,如果for语句庞大,执行次数多,估计JS引擎会发疯的~这种方法适合完成小任务,其对性能要求不高。

      翻译为字节码,与平台无关,需要相应的虚拟机环境。所谓的虚拟机就是用软件模拟出相应的硬件环境,由于不同类别计算机的硬件配置是不尽相同的,所以机器码编码方式是不同的,虚拟机可以很好的提高代码的跨平台性。此执行过程类似CPU操作,取指,译码,执行。每个操作对应一段代码,switch实现代码段跳转,用while实现循环执行switch语句操作。每执行一条语句就进行一次循环搜索,这对于进行大量操作的JS来说,太慢了。一般用查表方式直接跳转,通过将下条语句执行地址传入当前执行语句,执行完毕后,执行类似于goto的操作转入下条语句,以提高效率。

      即时编译(JIT),结合了例如C与C+的静态编译与JS的解释执行,即第一次运行将代码翻译成机器码,并保存已翻译的代码,下次执行相同代码时无需再次翻译。

      JS执行特性:加载后马上执行;执行时会阻碍后续内容进行,包括渲染与其他资源的下载。


    基本流程

      逐行扫描html,构建DOM树(解析html/svg/xhtml,css,js文件)->渲染树构建(结合DOM树与CSS规则树)->渲染布局(layout与reflow过程,计算每个元素确切位置)->绘制渲染树(调用本地GUI接口绘制每个节点元素)

      reflow:指浏览器根据各种样式计算并根据计算结果放置各元素相应的盒模型

      repaint:指各盒子的位置,大小,其他表现属性确定之后,浏览器按元素各自特性绘制元素

      为了更好的用户体验,浏览器力求尽快将内容显现出来,因此它会在解析后续内容时把已处理过的内容显示出来,若后续解码内容影响了已显示的内容,则回流reflow(改动节点)重绘repaint(改变样式),这是一个基于基本流程反复修正的过程,如果JS频繁操作节点元素会导致浏览器多次回流和重绘,所以应减少与DOM的交互请求,尽量避免改动DOM或者可以缓存DOM操作,以提高CPU性能。同时,给图片固定宽高可减少repaint。可千万别把浏览器整疯了~

  • 相关阅读:
    .Net开发中IIS启动后,网站不能访问。0x80004005 无法执行程序。所执行的命令为 .....问题
    .Net开发中项目无法引用/项目引用失败/引用文件出现黄色警告图标,并生成失败的问题
    Mac系统安装Docker
    小程序开发----微信小程序实现下拉刷新功能
    小程序开发----微信小程序navigate跳转没反应
    小程序开发----小程序点击复制文本内容到剪贴板
    小程序开发----微信小程序直接写&nbsp;设置空格无效
    python字符串的反转
    python2项目迁移到python3
    robotframework废弃的关键词以及替代的关键词(关键词找不到,可能已经过期了)
  • 原文地址:https://www.cnblogs.com/pada/p/3651725.html
Copyright © 2011-2022 走看看