About
JavaScript 是浏览器的内置脚本语言。也就是说,浏览器内置了 JavaScript 引擎,并且提供各种接口,让 JavaScript 脚本可以控制浏览器的各种功能。一旦网页内嵌了 JavaScript 脚本,浏览器加载网页,就会去执行脚本,从而达到操作浏览器的目的,实现网页的各种动态效果。
1. 如何确保外链的JavaScript脚本的完整性?
为了防止攻击者篡改外部脚本,script标签允许设置一个integrity属性,写入该外部脚本的 Hash 签名,用来验证脚本的一致性。
<script src="/assets/application.js"
integrity="sha256-TvVUHzSfftWg1rcfL6TIJ0XKEGrgLyEq6lEpcmrG9qs=">
</script>
上面代码中,script标签有一个integrity属性,指定了外部脚本/assets/application.js的 SHA256 签名。一旦有人改了这个脚本,导致 SHA256 签名不匹配,浏览器就会拒绝加载。
2. 浏览器识别并执行JavaScript脚本的原理?
这其实是一个网页渲染的过程:
- 浏览器一边下载HTML一边解析;
- 当发现<srcipt>标签的时候,浏览器就停止解析,并且把网页渲染的控制权交予JavaScript引擎;
- 如果此时<srcipt>中有外链的js文件,则开始下载js文件,且必须等待js文件下载完成后方可解释执行;
- JavaScript引擎执行完毕后再讲网页控制权交予渲染引擎,接着渲染下面的网页。
加载外部脚本时,浏览器会暂停页面渲染,等待脚本下载并执行完成后,再继续渲染。原因是 JavaScript 代码可以修改 DOM,所以必须把控制权让给它,否则会导致复杂的线程竞赛的问题。
如果外部脚本加载时间很长(一直无法完成下载),那么浏览器就会一直等待脚本下载完成,造成网页长时间失去响应,浏览器就会呈现“假死”状态,这被称为“阻塞效应”。
为了避免这种情况,较好的做法是将<script>标签都放在页面底部,而不是头部。这样即使遇到脚本失去响应,网页主体的渲染也已经完成了,用户至少可以看到内容,而不是面对一张空白的页面。如果某些脚本代码非常重要,一定要放在页面头部的话,最好直接将代码写入页面,而不是连接外部脚本文件,这样能缩短加载时间。
脚本文件都放在网页尾部加载,还有一个好处。因为在 DOM 结构生成之前就调用 DOM 节点,JavaScript 会报错,如果脚本都在网页尾部加载,就不存在这个问题,因为这时 DOM 肯定已经生成了。
3. 如果有多个<script>浏览器是如何处理的?
如果都是内嵌的JavaScript脚本,则按照顺序执行即可,如果是两个外链的js文件,比如:
<script src="a.js"></script>
<script src="b.js"></script>
那么浏览器会并行下载这两个脚本,但是执行顺序仍然是按照先a后b的顺序
4. defer属性和async属性的区别?
这两者都是为了避免因为下载js脚本导致的阻塞效应。
defer运行流程如下:
- 浏览器开始解析 HTML 网页。
- 解析过程中,发现带有defer属性的<script>元素。
- 浏览器继续往下解析 HTML 网页,同时并行下载<script>元素加载的外部脚本。
- 浏览器完成解析 HTML 网页,此时再回过头执行已经下载完成的脚本。
async运行流程:
- 浏览器开始解析 HTML 网页。
- 解析过程中,发现带有async属性的script标签。
- 浏览器继续往下解析 HTML 网页,同时并行下载<script>标签中的外部脚本。
- 脚本下载完成,浏览器暂停解析 HTML 网页,开始执行下载的脚本。
- 脚本执行完毕,浏览器恢复解析 HTML 网页。
两者的区别:
- 使用defer的脚本尽管下载完成后仍然需要等待html解析完成后才能执行,而async则是脚本下载完成后无论html是否解析完成立马执行。
- 使用defer的脚本无论哪一个先下载完,仍然按照写定的顺序去执行,而async则是哪一个先下载完就先执行哪一个。
<script src="a.js"></script>
<script src="b.js"></script>
一般来说,如果脚本之间没有依赖关系,就使用async属性,如果脚本之间有依赖关系,就使用defer属性。如果同时使用async和defer属性,后者不起作用,浏览器行为由async属性决定。
5. 浏览器的组成
浏览器由JavaScript引擎和渲染引擎组成。
不同的浏览器有不同的渲染引擎。
- Firefox:Gecko 引擎
- Safari:WebKit 引擎
- Chrome:Blink 引擎
- IE: Trident 引擎
- Edge: EdgeHTML 引擎
渲染引擎的工作流程:
- 解析代码:HTML 代码解析为 DOM,CSS 代码解析为 CSSOM(CSS Object Model)。
- 对象合成:将 DOM 和 CSSOM 合成一棵渲染树(render tree)。
- 布局:计算出渲染树的布局(layout)。
- 绘制:将渲染树绘制到屏幕。
6. 常见的JavaScript引擎
- Chakra (Microsoft Internet Explorer)
- Nitro/JavaScript Core (Safari)
- Carakan (Opera)
- SpiderMonkey (Firefox)
- V8 (Chrome, Chromium)
网友评论