1. 解析代码:HTML代码解析为DOM,CSS代码解析为CSSOM(CSS Object Model)
1. 对象合成:将DOM和CSSOM合成一棵渲染树(render tree)
1. 布局:计算出渲染树的布局(layout)
1. 绘制:将渲染树绘制到屏幕
以上四步并非严格按顺序执行,往往第一步还没完成,第二步和第三步就已经开始了。所以,会看到这种情况:网页的HTML代码还没下载完,但浏览器已经显示出内容了。
(2)JavaScript引擎
JavaScript引擎的主要作用是,读取网页中的JavaScript代码,对其处理后运行。
本节主要介绍JavaScript引擎的工作方式。
## JavaScript代码嵌入网页的方法
JavaScript代码只有嵌入网页,才能运行。网页中嵌入JavaScript代码有多种方法。
### 直接添加代码块
通过`
`
如果脚本文件使用了非英语字符,还应该注明编码。
```html
加载外部脚本和直接添加代码块,这两种方法不能混用。下面代码的`console.log`语句直接被忽略。
```html
为了防止攻击者篡改外部脚本,`script`标签允许设置一个`integrity`属性,写入该外部脚本的Hash签名,用来验证脚本的一致性。
```html
上面代码中,`script`标签有一个`integrity`属性,指定了外部脚本`/assets/application.js`的SHA265签名。一旦有人改了这个脚本,导致SHA265签名不匹配,浏览器就会拒绝加载。
除了JavaScript脚本,外部的CSS样式表也可以设置这个属性。
### 行内代码
除了上面两种方法,HTML语言允许在某些元素的事件属性和`a`元素的`href`属性中,直接写入JavaScript。
```html
这种写法将HTML代码与JavaScript代码混写在一起,非常不利于代码管理,不建议使用。
## script标签的工作原理
正常的网页加载流程是这样的。
1. 浏览器一边下载HTML网页,一边开始解析
1. 解析过程中,发现script标签
1. 暂停解析,网页渲染的控制权转交给JavaScript引擎
1. 如果script标签引用了外部脚本,就下载该脚本,否则就直接执行
1. 执行完毕,控制权交还渲染引擎,恢复往下解析HTML网页
也就是说,加载外部脚本时,浏览器会暂停页面渲染,等待脚本下载并执行完成后,再继续渲染。原因是JavaScript可以修改DOM(比如使用`document.write`方法),所以必须把控制权让给它,否则会导致复杂的线程竞赛的问题。
如果外部脚本加载时间很长(比如一直无法完成下载),就会造成网页长时间失去响应,浏览器就会呈现“假死”状态,这被称为“阻塞效应”。
为了避免这种情况,较好的做法是将script标签都放在页面底部,而不是头部。这样即使遇到脚本失去响应,网页主体的渲染也已经完成了,用户至少可以看到内容,而不是面对一张空白的页面。
如果某些脚本代码非常重要,一定要放在页面头部的话,最好直接将代码嵌入页面,而不是连接外部脚本文件,这样能缩短加载时间。
将脚本文件都放在网页尾部加载,还有一个好处。在DOM结构生成之前就调用DOM,JavaScript会报错,如果脚本都在网页尾部加载,就不存在这个问题,因为这时DOM肯定已经生成了。
```html
上面代码执行时会报错,因为此时`body`元素还未生成。
一种解决方法是设定`DOMContentLoaded`事件的回调函数。
```html
另一种解决方法是,使用`script`标签的`onload`属性。当script标签指定的外部脚本文件下载和解析完成,会触发一个load事件,可以把所需执行的代码,放在这个事件的回调函数里面。
```html
但是,如果将脚本放在页面底部,就可以完全按照正常的方式写,上面两种方式都不需要。
```html