关于javascript:浏览器工作原理与实践五

6次阅读

共计 3228 个字符,预计需要花费 9 分钟才能阅读完成。

DOM解析器不是等文档加载实现才解析的,而是边加载边解析。
网络过程依据收到的 content-type=text/html 判断是 html 类型,为该申请创立一个渲染过程,渲染过程筹备好后会在网络过程和渲染过程中建设一个共享数据的管道,网络过程按收到的字节流像水一样的倒进这个管道,渲染过程的 html 解析器会动静接管字节流将其解析为 DOM
字节流Bytes——> 分词器Tokens——> 生成节点Node——>DOM

  1. 通过分词器将字节流转换成 Token,分为TagToken(StartTag、EndTag) 和文本Token
  2. Token 解析为 DOM 节点,增加到 DOM 树,Html中有一个 Token 栈构造,第一步中生成的 Token 都会进入这个栈中。如果是 StartTagHtml 解析器会为 Token 创立一个 Dom 节点,而后退出到 DOM 树中。如果是文本 Token,会生成一个文本节点退出DOM 树中,不必压入栈。如果是 EndTagHtml 会查看栈顶元素有没有它的StartTag,有就从栈顶弹出,示意该元素解析实现。

如果在 2 段 div 中插入 script,解析到(script) 会暂停 DOM 解析,JS脚本实现后,Html解析器复原继续执行。渲染过程接管字节流时,也会开启一个预解析线程,遇到 JSCSS文件预解析线程会提前下载这些数据。申请 Html 到构建 DOM 之间有一段闲暇工夫,构建 DOM 树之后 css 未下载完之前也会有一段闲暇工夫,可能会有白屏。

<html>
    <head><link href="them.css" rel="stylesheet" /></head>
    <body>
        <div>segmentfault.com</div>
        <script src="foo.js"></script>
        <div> 思否 </div>
    </body>
</html>

解析 Html、下载CSS、下载JS、生成CSSOM、执行JS、生成布局树、绘制页面。
次要空白:下载 CSS、下载JS、执行JShtml 下载
策略:1. 内联 JS,css 移除下载。2. 缩小文件大小、webpack移除正文,压缩、JSdeferasynccss合成
优化:

  1. 加载阶段:网络,JS脚本,图片,音频,视频文件不会阻塞页面首次渲染。JS,html,css文件会阻塞。构建 DOM 须要 HtmlJS,构建渲染树须要 CSS
    (1). 要害资源个数:数据越多,首次加载工夫越长。1. 改成内联。2.JS 没有 DOMCSS操作,加 deferasynccssmadio
    (2). 资源大小:资源越小,下载工夫越短。压缩css,js 资源。移除正文。
    (3). RTT数量:传输分包,小于 14k 只用 1 个 RTTRTT 次数越多,申请工夫越长,缩小个数或大小。CDN缩小时长。
  2. 交互阶段:JS脚本,渲染过程渲染帧的速度。
    (1). 缩小 JS 脚本执行工夫:1. 执行函数合成多个工作。2.web workers。不要霸占主线程太久。
    (2). 防止强制同步布局:通过 DOM 接口,增加删除元素,须要从新计算款式和布局。批改 DOM 前查问相干值。同步布局:JS强制将计算款式和布局操作提前到当前任务中。如加个元素,而后获取此元素高度,获取就要布局后能力获取。
    (3). 防止布局抖动:一次 JS 执行中,屡次强布局和抖动。如 for 循环中,一直读取属性值,每次读都要进行计算款式和布局。不要在批改 DOM 时再去查相干值。
    (4). 正当利用 css 合成动画,css合成动画在合成线程上执行。不受主线程限度,尽量用 css 合成动画。
    (5). 防止频繁垃圾回收,垃圾回收时会占用主线程。优化存储构造,防止小颗粒对象的产生。

DOM的缺点:
DOM提供了一组 JS 接口来遍历或批改节点。JS操作 DOM 会影响到整个渲染流水线。如 document.body.appendChild(node),往body 节点增加一个元素,首先渲染引擎将 node 增加到 body 之上,而后触发款式计算、布局、绘制、栅格化。布局和布局抖动问题,会大大降低渲染效率。
虚构 DOM 通过 JS 和根底数据创立虚构 DOM,由虚构DOM 创立出实在 DOM 树,再触发渲染流水线输入屏幕。如果产生扭转就依据新数据创立新的虚构 DOM,而后比拟 2 颗虚构DOM 找出变动,再把所有变动一次性从新更新实在 DOM 树上,更新渲染流水线,生成新页面。
react之前的递归算法比拟多的话会占主线程比拟久,造成卡页面。Fiber又叫协程,执行算法的时候让出主线程,解决占用工夫久的问题。双缓存,先将计算结果放在另一个缓存区,全副计算完再把后果利用到 DOM 上,缩小不必要更新。

渲染引擎会将所有的 css 内容解析为 CSSOM。生成布局树的时候,会在CSSOM 中为布局树元素查找款式,2 个雷同标签显示的成果会是一样的,渲染引擎不会为他们独自设置款式。
css会影响到 DOM 中其它同样标签的款式。JS也能在任何中央批改DOM。是妨碍组件化的 2 个因素。

webComponent是一套技术的组合,Custom elements(自定义元素)、shadow DOM(影子 DOM)、Html templates(Html 模板)。
webComponent提供了对部分视图封装能力,能够让 DOMCSSOMJS 运行在部分环境,不会影响到全局。
微服务框架 qiankun 就是用的这个。
新建一个组件:1. 定义模板。2. 定义外部 css 款式。3. 定义 JS 行为

<!DOCTYPE html>
<html>
  <body>
    <template id="template">
      <style>
        p{
          background-color: brown;
          color: cornsilk;
        }
        div{
          width: 200px;
          background-color: bisque;
        }
      </style>
      <div>
        <p>text1</p>
        <p>text2</p>
      </div>
      <script>
        function foo(){console.log('inner log')
        }
      </script>
    </template>
    <script>
      class ShadowDomTemplate extends HTMLElement{constructor(){super();
          // 获取组件模板
          const content=document.querySelector('#template').content;
          // 创立影子 DOM 节点
          const shadowDom=this.attachShadow({mode:'open'});
          // 将模板增加到影子 DOM 上
          shadowDom.appendChild(content.cloneNode(true));
        }
      }
      customElements.define('temp-component',ShadowDomTemplate);
    </script>
    <temp-component></temp-component>
  </body>
</html>

渲染出:

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <template id="template">
      #document-fragment
    </template>
    <script></script>
    <temp-component>
      #shadow-root(open)
      <style>...</style>
      <div>...</div>
    </temp-component>
  </body>
</html>

影子 DOM 元素对网页不可见。
影子 DOM 的作用将模板中内容与全局 DOMcss进行隔离,实现元素和款式私有化。能够把影子 DOM 看成一个作用域,外部款式和元素不会影响全局。全局下要拜访影子内款式元素,通过约定好的接口,互不影响。
只通过影子 DOM 隔离 cssDOM,但不会隔离 JSJS 能够被拜访,渲染引擎判断 temp-componentshadow-root,如是影子 DOM 会跳过,款式也只会从外部找。

正文完
 0