知识点梳理
- 浏览器加载页面和渲染过程
- 性能优化
- Web 安全
本小节会从浏览器的加载过程开始讲解,然后介绍如何进行性能优化,最后介绍下 Web 开发中常见的安全问题和预防。
加载页面和渲染过程
可将加载过程和渲染过程分开说。回答问题的时候,关键要抓住核心的要点,把要点说全面,稍加解析即可,简明扼要不拖沓。
题目:浏览器从加载页面到渲染页面的过程
加载过程
要点如下:
- 浏览器根据 DNS 服务器得到域名的 IP 地址
- 向这个 IP 的机器发送 HTTP 请求
- 服务器收到、处理并返回 HTTP 请求
- 浏览器得到返回内容
server 端接收到 HTTP 请求,然后经过计算(向不同的用户推送不同的内容),返回 HTTP 请求,返回的内容如下:
其实就是一堆 HMTL 格式的字符串,因为只有 HTML 格式浏览器才能正确解析,这是 W3C 标准的要求。接下来就是浏览器的渲染过程。
渲染过程
要点如下:
- 根据 HTML 结构生成 DOM 树
- 根据 CSS 生成 CSSOM
- 将 DOM 和 CSSOM 整合形成 RenderTree
- 根据 RenderTree 开始渲染和展示
- 遇到`<script>`时,会执行并阻塞渲染
上文中,浏览器已经拿到了 server 端返回的 HTML 内容,开始解析并渲染。最初拿到的内容就是一堆字符串,必须先结构化成计算机擅长处理的基本数据结构,因此要把 HTML 字符串转化成 DOM 树 —— 树是最基本的数据结构之一。
解析过程中,如果遇到`<link href="...">`和`<scriptsrc="...">`这种外链加载 CSS 和 JS 的标签,浏览器会异步下载,下载过程和上文中下载 HTML 的流程一样。只不过,这里下载下来的字符串是 CSS 或者 JS 格式的。
浏览器将 CSS 生成 CSSOM,再将 DOM 和 CSSOM 整合成 RenderTree ,然后针对 RenderTree 即可进行渲染了。大家可以想一下,有 DOM 结构、有样式,此时就能满足渲染的条件了。另外,这里也可以解释一个问题 —— **为何要将 CSS 放在 HTML 头部?**—— 这样会让浏览器尽早拿到 CSS 尽早生成 CSSOM,然后在解析 HTML 之后可一次性生成最终的 RenderTree,渲染一次即可。如果 CSS 放在 HTML 底部,会出现渲染卡顿的情况,影响性能和体验。
最后,渲染过程中,如果遇到`<script>`就停止渲染,执行 JS 代码。因为浏览器渲染和 JS 执行共用一个线程,而且这里必须是单线程操作,多线程会产生渲染 DOM 冲突。待`<script>`内容执行完之后,浏览器继续渲染。最后再思考一个问题 —— **为何要将 JS 放在 HTML 底部?**—— JS 放在底部可以保证让浏览器优先渲染完现有的 HTML 内容,让用户先看到内容,体验好。另外,JS 执行如果涉及 DOM 操作,得等待 DOM 解析完成才行,JS 放在底部执行时,HTML 肯定都解析成了 DOM 结构。JS 如果放在 HTML 顶部,JS 执行的时候 HTML 还没来得及转换为 DOM 结构,可能会报错。
关于浏览器整个流程,百度的多益大神有更加详细的文章,推荐阅读下:《[从输入 URL 到页面加载完成的过程中都发生了什么事情?
](http://fex.baidu.com/blog/2014/05/what-happen/)》。
性能优化
性能优化的题目也是面试常考的,这类题目有很大的扩展性,能够扩展出来很多小细节,而且对个人的技术视野和业务能力有很大的挑战。这部分笔者会重点讲下常用的性能优化方案。
题目:总结前端性能优化的解决方案
优化原则和方向
性能优化的原则是**以更好的用户体验为标准**,具体就是实现下面的目标:
- 多使用内存、缓存或者其他方法
- 减少 CPU 和GPU 计算,更快展现
优化的方向有两个:
- 减少页面体积,提升网络加载
- 优化页面渲染
减少页面体积,提升网络加载
- 静态资源的压缩合并(JS 代码压缩合并、CSS 代码压缩合并、雪碧图)
- 静态资源缓存(资源名称加 MD5 戳)
- 使用 CDN 让资源加载更快
优化页面渲染
- CSS 放前面,JS 放后面
- 懒加载(图片懒加载、下拉加载更多)
- 减少DOM 查询,对 DOM 查询做缓存
- 减少DOM 操作,多个操作尽量合并在一起执行(`DocumentFragment`)
- 事件节流
- 尽早执行操作(`DOMContentLoaded`)
- 使用 SSR 后端渲染,数据直接输出到 HTML 中,减少浏览器使用 JS 模板渲染页面 HTML 的时间
详细解释
静态资源的压缩合并
如果不合并,每个都会走一遍之前介绍的请求过程
<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>
如果合并了,就只走一遍请求过程
<script src="abc.js"></script> 静态资源缓存
通过链接名称控制缓存
<script src="abc_1.js"></script> 只有内容改变的时候,链接名称才会改变
<script src="abc_2.js"></script>
这个名称不用手动改,可通过前端构建工具根据文件内容,为文件名称添加 MD5 后缀。
使用 CDN 让资源加载更快
CDN 会提供专业的加载优化方案,静态资源要尽量放在 CDN 上。例如:
<script src="https://cdn.bootcss.com/zepto/1.0rc1/zepto.min.js"></script> 使用 SSR 后端渲染
可一次性输出 HTML 内容,不用在页面渲染完成之后,再通过 Ajax 加载数据、再渲染。例如使用 smarty、Vue SSR 等。
CSS 放前面,JS 放后面
上文讲述浏览器渲染过程时已经提过,不再赘述。
懒加载
一开始先给为 `src` 赋值成一个通用的预览图,下拉时候再动态赋值成正式的图片。如下,
`preview.png`是预览图片,比较小,加载很快,而且很多图片都共用这个`preview.png`,加载一次即可。待页面下拉,图片显示出来时,再去替换`src`为`data-realsrc`的值。
<img src="preview.png" data-realsrc="abc.png"/>
另外,这里为何要用`data-`开头的属性值?—— 所有 HTML 中自定义的属性,都应该用`data-`开头,因为`data-`开头的属性浏览器渲染的时候会忽略掉,提高渲染性能。