JavaScript 复习之浏览器模型

302 阅读4分钟

网页中嵌入 JavaScript 代码,主要有三种方法。

  • <script>元素直接嵌入代码。

  • <script>标签加载外部脚本

  • 事件属性

  • URL 协议

script 元素

工作原理

  1. 浏览器一边下载 HTML 网页,一边开始解析。也就是说,不等到下载完,就开始解析。
  2. 解析过程中,浏览器发现<script>元素,就暂停解析,把网页渲染的控制权转交给 JavaScript 引擎。
  3. 如果<script>元素引用了外部脚本,就下载该脚本再执行,否则就直接执行代码。
  4. JavaScript 引擎执行完毕,控制权交还渲染引擎,恢复往下解析 HTML 网页。

defer属性

他的作用是延迟脚本执行,等到 DOM 加载生成后,在执行脚本。

defer属性的运行流程如下。

  1. 浏览器开始解析 HTML 网页。
  2. 解析过程中,发现带有defer属性的<script>元素。
  3. 浏览器继续往下解析 HTML 网页,同时并行下载<script>元素加载的外部脚本。
  4. 浏览器完成解析 HTML 网页,此时再回过头执行已经下载完成的脚本。

async属性

解决“阻塞效应”的另一个方法是对<script>元素加入async属性。

async属性的作用是,使用另一个进程下载脚本,下载时不会阻塞渲染。

  1. 浏览器开始解析 HTML 网页
  2. 解析过程中,发现带有async属性的script标签
  3. 浏览器继续往下解析 HTML 网页,同时并行下载<script>标签中的外部脚本。
  4. 脚本下载完成,浏览器停止解析 HTML 网页,开始执行下载的脚本
  5. 脚本执行完毕,浏览器恢复解析 HTML 网页

async属性可以保证脚本下载的同时,浏览器继续渲染。需要注意的是,一旦采用这个属性,就无法保证脚本的执行顺序。哪个脚本先下载结束,就先执行那个脚本。另外,使用async属性的脚本文件里面的代码,不应该使用document.write方法。

脚本加载使用的协议

如果不指定协议,浏览器默认采用 HTTP 协议下载。

<script src="example.js"></script>

上面的example.js默认就是采用 HTTP 协议下载,如果要采用 HTTPS 协议下载,必需写明。

<script src="https://example.js"></script>

但是有时我们会希望,根据页面本身的协议来决定加载协议,这时可以采用下面的写法。

<script src="//example.js"></script>

浏览器的组成

浏览器的核心是两部分:渲染引擎和JavaScript引擎

渲染引擎的主要作用是将网页代码渲染为用户视觉可以感知的平明文档。处理网页分为四个阶段:

  1. 解析代码:HTML 代码解析为 DOM , CSS代码解析为 CSSOM
  2. 对象合成:将 DOM 和 CSSOM 合成一个渲染树
  3. 布局:计算渲染树的布局
  4. 绘制:将渲染树绘制到屏幕

重流和重绘

渲染树转换为网页布局,称为“布局流”;布局显示到页面的过程称为“绘制”。

页面生成以后,脚本操作和样式表操作,都会触发“重流”和“重绘”。

重流和重绘并不一定一起发生,重流必然导致重绘,重绘不一定需要重流。

优化技巧:

  • 读取 DOM 或者写入 DOM,尽量写在一起,不要混杂。不要读取一个 DOM 节点,然后立刻写入,接着再读取一个 DOM 节点。

  • 缓存 DOM 信息。

  • 不要一项一项地改变样式,而是使用 CSS class 一次性改变样式。

  • 使用documentFragment操作 DOM ``动画使用absolute定位或fixed定位,这样可以减少对其他元素的影响。

  • 只在必要时才显示隐藏元素。

  • 使用window.requestAnimationFrame(),因为它可以把代码推迟到下一次重流时执行,而不是立即要求页面重流。

  • 使用虚拟 DOM(virtual DOM)库。

// 重绘代价高
function doubleHeight(element) {
  var currentHeight = element.clientHeight;
  element.style.height = (currentHeight * 2) + 'px';
}

all_my_elements.forEach(doubleHeight);

// 重绘代价低
function doubleHeight(element) {
  var currentHeight = element.clientHeight;

  window.requestAnimationFrame(function () {
    element.style.height = (currentHeight * 2) + 'px';
  });
}

all_my_elements.forEach(doubleHeight);

avaScript 引擎的主要作用是,读取网页中的 JavaScript 代码,对其处理后运行。