参考自: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。