【前端学习笔记】浏览器的渲染过程,阻塞渲染,

参考自:https://juejin.im/entry/59e1d31f51882578c3411c77

浏览器请求,加载,渲染一个页面(url请求,到页面生成的过程):

1,DNS查询

2,TCP连接

3,HTTP请求即响应

4,服务器响应

5,客户端-浏览器解析,渲染页面

在第五部分,浏览器对内容的渲染,这一部分,渲染树构建,布局以及绘制。分为5个步骤

1,处理HTML标记并构建DOM树;

2,处理CSS标记并构建CSSOM树(CSS对象模型);

3,将DOM与CSSOM合并成一个渲染树(Render-Tree);

4,根据渲染树来布局,以计算每个节点的几何信息;

5,将每个节点绘制到屏幕上;

在实际页面中,CSS与JavaScript往往会多次修改DOM和CSSOM。

阻塞渲染:CSS与JavaScript

现代浏览器总是并行加载资源,例如当HTML解析器被脚本阻塞时,虽然解析器会停止构建DOM,但仍会识别该脚本后面的资源,并进行预加载。

JavaScript不仅会读取和修改DOM属性,还可以读取修改CSSOM属性。JavaScript可以查询和修改DOM和CSSOM。

存在阻塞的CSS资源时,浏览器会延迟JavaScript的执行和DOM的构建,另外

1,当浏览器遇到script的标记,DOM构建将暂停,直到脚本完成执行;

2,CSSOM构建时,JavaScript执行暂停,直到CSSOM就绪。

所以script的标签位置很重要,实际使用时遵循原则:

1,CSS优先,引入顺序上CSS资源优先于JavaScript资源;2,JavaScript尽量少影响DOM构建;

渲染树的关键渲染路径中,要求同时具有DOM和CSSOM,之后才会构建渲染树,即HTML和CSS都是阻塞渲染的资源。

HTML必要,因为文本这类内容都在DOM中存放,所以从优化CSS上想办法。

精简CSS并尽快提供,另外可以利用媒体类型(media),媒体查询(media query)来接触对渲染的阻塞;

<link href="other.css" rel="stylesheet" media="print">
<link href="other.css" rel="stylesheet" media="(min-width:30em) and (orientation: landscape)">

改变阻塞模式:defer 与 async

async和defer对于inline-script都是无效的。就是不含有src属性的script的标签。

defer表示延迟执行引入的javascript,即加载时HTML并未停止解析,并行。等document解析完毕且defer-script也加载完成后,才会执行所有由defer-script加载的JavaScript代码,然后触发DOMContentLoaded事件。

defer不会改变script中代码的执行顺序。

特点是:载入JavaScript文件时不会阻塞HTML解析,在之后才会执行JavaScript的加载;

Async表示异步执行引入的JavaScript,与defer区别在于,如果已经加载后,就会立刻执行,无论此时HTML解析阶段还是DOMContentLoaded触发以后。

所以这种方式可能会阻塞load事件。

document.createElement

使用 document.createElement 创建的 script 默认是异步的,示例如下。

console.log(document.createElement("script").async); // true

所以,通过动态添加 script 标签引入 JavaScript 文件默认是不会阻塞页面的。如果想同步执行,需要将 async 属性人为设置为 false。

如果使用 document.createElement 创建 link 标签会怎样呢?

const style = document.createElement("link");
style.rel = "stylesheet";
style.href = "index.css";
document.head.appendChild(style); // 阻塞?

其实这只能通过试验确定,已知的是,Chrome 中已经不会阻塞渲染,Firefox、IE 在以前是阻塞的,现在会怎样我没有试验。

document.write 与 innerHTML

通过 document.write 添加的 link 或 script 标签都相当于添加在 document 中的标签,因为它操作的是 document stream(所以对于 loaded 状态的页面使用 document.write 会自动调用 document.open,这会覆盖原有文档内容)。即正常情况下, link 会阻塞渲染,script 会同步执行。不过这是不推荐的方式,Chrome 已经会显示警告,提示未来有可能禁止这样引入。如果给这种方式引入的 script 添加 async 属性,Chrome 会检查是否同源,对于非同源的 async-script 是不允许这么引入的。

如果使用 innerHTML 引入 script 标签,其中的 JavaScript 不会执行。当然,可以通过 eval() 来手工处理,不过不推荐。如果引入 link 标签,我试验过在 Chrome 中是可以起作用的。另外,outerHTML、insertAdjacentHTML() 应该也是相同的行为,我并没有试验。这三者应该用于文本的操作,即只使用它们添加 text 或普通 HTML Element。

猜你喜欢

转载自blog.csdn.net/weixin_41835977/article/details/88878226