SPOF的简单示例
只是在页面上添加一个脚本或者一个样式,也许就会让大部分用户无法正常使用。比起考虑CSS错误或者JS报错的情况,核心问题在于如果这个新添加的资源文件超时,会发生什么?有了这个线索,我们可以构建一个测试用例:
<html>
<head>
<script src="http://www.snippet.com/main.js" type="text/javascript">
</script>
</head>
<body>
Here's my page!
</body>
</html>
页面看上去很简单,如果 snippet.com 这个站点超载了,页面将会持续空白,等待 main.js 返回。下图是一些单点故障(SPOF)的示例,以及在不同浏览器下的影响,图片年代久远,仅供参考:
红色标注的是SPOF的情况,以下是从最坏到最好的四种可能的结果:
- totally blank: 页面什么都没渲染,完全空白
- blank below: 该资源下方的所有dom都未渲染
- delayed: 使用自定义字体的文字不可见,直到字体文件下载完成后展示
- flash: dom立刻渲染,等到样式文件或者字体下载完成,视情况重新渲染样式
如何避免SPOF?
事实证明,有一些Web性能最佳实践,除了可以让你页面变得更快之外,还可以避免大多数前端单点故障。
外部脚本
所有浏览器都会阻止外部脚本以下的dom渲染,直到该脚本下载并执行,然而还是有很多人把脚本放在 <head>
标签中,一旦该脚本超时,整个页面都会空白。最佳的Web性能实践就是异步加载这些脚本,不仅可以提升页面的加载速度,也能避免单点故障。
样式
浏览器在样式渲染上有所不同。FireFox和Opera会先渲染dom,等样式加载完再视情况重新渲染,而chrome、IE和safari则是等待样式加载完,再去渲染dom。如果样式文件超时,页面渲染被阻塞,用户只能看到白页了。在不阻止页面渲染的情况下加载样式的建议不多,因为这会造成内容闪烁的问题。
内联样式的自定义字体
如果自定义字体定义在内联样式中,单点故障会大大减少。FireFox、IE和Opera会先渲染文本,等自定义字体加载完,在重新渲染,但chrome和safari直到字体文件下载完才会相关文本,对于这些浏览器的用户,遇到问题的话就不能正常使用了。考虑到一般网站都只是部分文本使用自定义字体,这类问题的影响不会太大。
外部样式的自定义字体
把自定义字体定义在内联样式中,是避免单点故障的关键,因为如果字体文件超时,也仅仅是应用这些字体的文字不可见,至少页面其余部分是可见的。如果把自定义字体定义在外部样式中,不仅降低了你的网页的打开速度(需要2个顺序的请求来渲染文本),而且如果样式文件超时,该资源以下的dom将无法渲染,如果你的样式文件在 <head>
标签中,则完全空白了。
如何测试SPOF?
其实测试方式很简单,只要模拟一下这类超时的请求即可,需要一个黑洞服务器,你的请求发过去不会有任何响应那种,以下就是个示例:
blackhole.webpagetest.org (aka 72.66.115.13)
黑洞服务器指的就是请求可以到达,但都会被服务器丢掉,浏览器收不到任何响应。
然后绑定host:
72.66.115.13 ajax.googleapis.com
72.66.115.13 apis.google.com
72.66.115.13 www.google-analytics.com
72.66.115.13 connect.facebook.net
72.66.115.13 platform.twitter.com
这样,和上面相关资源就会超时了,当然还有更优雅的方式,具体的可以参考 https://blog.patrickmeenan.co...
总结
很多时候,我们都会把焦点放在后端的性能上,觉得只要后端接口能够快速返回就可以让用户更快的看到页面,而忽视了一些前端细节,可能因为你的一次第三方库的引入,就导致了SPOF,平时多问问自己:
- 你的站点是不是一定要依赖这些资源?
- 如果其中一个资源超时了,用户能不能看到内容?
- 这些SPOF都是来自第三方库吗?
- 在使用一些内嵌的资源的时候,考虑过如何避免SPOF吗?
对SPOF时刻保持警惕,引入第三方库的时候尽可能用无阻塞的方式。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。