前端性能优化指南

时间:2022-12-09 18:14:31

在“A Node.JS Holiday Season”系列丛书的这一章中,我们将会讨论一些前端性能和介绍一些基于Mozilla的快速开发工具。

我们将要使用前段性能自动化中非常重要的工具之一的connect-cachify

开始之前,让我们简要重述一下作为开发者如何让机器运行的更稳定。如果你已经了解前端最优化的方法,请跳过前面的部分,了解如何使用connect-cachify完成自动化功能。

 

3c 客户端性能优化

网站上到处都是与性能优化相关的最佳实践的信息。虽然存在许多先进的技术可以为你的网站调整每一毫秒,但有三种基本工具是最基础的——连接、压缩和缓存。

 

连接

连接的目标是尽量减少对服务器发出的请求数量。服务器请求是昂贵的。建立一个HTTP连接所需的时间有时比传送数据本身所花的时间还要多。每个请求增加很多用于检测你的网站的开销,尤其是在移动设备上,这会造成显著的连接延迟。你是否用手机通过Edge网络浏览过一个购物网站,上面的图片一个一个蹦出来?这就是连接延时的现象。


 

SPDY是一个构建在HTTP协议之上的新协议,旨在通过合并多个资源请求到一个单一的HTTP请求来减少页面加载时间。不幸的是,目前只有最新版本的Firefox、Chrome和Opera浏览器支持这个新协议。

尽可能的合并外部资源,可能方法过时,但是可以跨浏览器工作,并且不会因为SPDY的到来而退化。已经有很多用来合并JavaScript、CSS和图片这三种最常见外部资源的工具。

 

JavaScript & CSS

当一个网站有多个外部的JS时,需要把他们合并成一个文件。在JS加载完成前,浏览器会阻止掉所有的渲染。(也就是你看不到JS的效果)。被请求的JS文件将会出现延迟,比如执行下面的代码将会花费更长的时间。

<scriptsrc="jquery.min.js"></script>
<scriptsrc="main.js"></script>
<scriptsrc="image-carousel.js"></script>
<scriptsrc="widget.js"></script>
把四个Js文件整合成一个,将会减少延迟时间。(像下面这样)
1 <scriptsrc="main.production.js"></script>
使用整合过的JS有一点难度,所以大多数情况下,使用在正式的项目中。

Css和进程也是一样,在做项目的时候也应该整合到一起。

 
Images

Data URIs和image sprites减少请求图片的两种基本方法。

data: URI

data URI一个URL的特殊形式,直接把图片嵌入到HTML或者CSS里面。Data URIs可以作为img的src标签或者是CSS中background-image的url值。因为嵌入图片是基于base64编码的,所以他们需要更多的空间,好处是比之前的二进制图像少了一次HTTP请求。所以,当要嵌入的图片很小时,由于图片编码产生的大小往往被减少一次HTTP请求所抵消。

注:IE6和IE7都不支持 data URIs

 

Image sprites

Image sprites在data URI不能用的时候会是一个很好的选择。image sprite是用很多小图像组合而成的一张大图片。一旦这个图片生成后,CSS就可以用来显示指定部分的图片。许多工具都是用来做这种图片的。

缺点是维护起来麻烦,当你要添加、删除或者修改一个图片时,你需要修改其对应的CSS。

Sprite Cow帮你获得sprites 的 background-position, width and height并生成一个可复制的css表。

 

删掉多余的字节 – 精简,优化,压缩

组合资源,减少访问次数可以有效的提升访问速度,除此之外,也应该精简向用户传递的数据。 精简,优化,压缩也是减少字节的通常做法。

JavaScript & CSS

JavaScript和CSS作为文本资源,可以通过去除浏览器中无关的代码实现精简一般情况下,JS和CSS采用的方法是删掉多余的注释和空格。JS的精简更加复杂,一些人删掉命名规则中的不必要的部分,把变量的命名缩短,甚至有人用更短的代码替换较长的代码来实现。

UglifyJSYUICompressor还有Google Closure Compiler是三个常用的JS精简工具。

YUICompressor and UglifyCSS是两个CSS精简工具。

 

Images Optimization

图片中包含一些数据,移除也不会影响视觉效果。清除这些数据需要专业的图片处理工具。我们的Francois Marier写了两篇博客文章讲解处理PNG图片GIF图片

Smush.it是雅虎的在线图片优化工具。OSX的离线工具ImageOptim也有同样的功能-将图片拖入,工具自动优化图片文件大小。ImageOptim还可以用处理后的小文件替换原始文件。

如果可以接受视觉效果的适度损失,高压缩比重新压缩图片也是可行的。

 
服务器也可以帮忙!

除了合并和缩小资源外,还有其他办法。几乎所有的服务器和浏览器都支持 HTTP 压缩 功能。最受欢迎的两种压缩方案是使用 deflate 和 gzip。在数据被服务器传送到客户端前,这两种方案都使用了高效的压缩算法来压缩被传送的资源以达到减少传送数据的目的。

 

缓存

拼接(Concatenation)和压缩(Compression)可以改善用户的第一次访问。缓存(Caching)优化了用户的回访。再一次访问时不需要重新下载所有的资源文件。HTTP协议提供了两种方式实现缓存机制,缓存头和ETags。

缓存头可以缓存经常修改的资源。它包含两个部分:Expires和Cache-Control:max-age。Expires标记过期时间,此后的访问将重新请求资源。max-age表示资源的有效秒数。当带有缓存头时,浏览器只会在缓存头过期后重新请求资源。

 

ETag表示资源的版本,用于与服务器比对是否相同。它适用于任意改变的内容资源。资源的ETag头告诉浏览器“去问问服务器有同人没,如果有就不改写啦!”。但是ETag还需要和服务器交互,不太适用于完全缓存的资源。

 

缓存破坏

相对于ETag,基于时间的Cache-Control头的优势在于只在过期后请求资源。但这也是最大的缺陷。如果资源改变了(但缓存头没过期),我们需要一些方法破坏缓存。

破坏缓存通常的方法是资源URL添加版本号。URL的改变会抛弃原有的缓存头重新请求资源。

例如资源http://example.com/logo.png的缓存头过期时间是一年,但logo更新了。已经缓存logo的用户在一年后才看到新logo。添加版本标识就可以避免这个情况:

旧的logo

http://example.com/v8125/logo.png

或者

http://example.com/logo.png?v8125
更换新logo后,修改版本信息以重新请求资源
http://example.com/v8126/logo.png
或者
http://example.com/logo.png?v8126
 

Connect-cachify —— 一个用来服务串联缓存资源的NodeJS
Connect-cachify 是一个由Mozilla开发的NodeJS中间件,用来简化提供正确的链接和缓存的资源的任务

在生产模式下Connect-cachify提供带一年高速缓存生产资源的预生成如果在生产模式下,取而代之的则是个人开发资源来避免调试变得复杂。Connect-cachify自己不进行字串串联极简化全靠你在构建脚本中进行


可以通过setup函数配置connect-cacheify。setup函数有两个参数,asset与options。asset是一种产品资源文件与开发资源文件的对应关系。每一个产品资源文件关联于一系列单独的开发资源文件。

options有以下设置参数:

  • prefix——加于hash码之前的前缀字符串。(默认为空)
  • production——由开发资源还是产品资源输出。(默认为true)
  • root——访问静态资源的根路径,这个与之前中间件的路径一致。(默认为'.',当前路径)
 

connect-cachify 实例

首先,让我们为connect-cachify准备一个简单的HTML文件。文件引入了3个CSS文件和3个Javascript文件。

...
<head>
  <title>Dashboard: Hamsters of North America</title>
  <linkrel="stylesheet"type="text/css"href="/css/reset.css"/>
  <linkrel="stylesheet"type="text/css"href="/css/common.css"/>
  <linkrel="stylesheet"type="text/css"href="/css/dashboard.css"/>
</head>
<body>
  ...
  <scripttype="text/javascript"src="/js/lib/jquery.js"></script>
  <scripttype="text/javascript"src="/js/magick.js"></script>
  <scripttype="text/javascript"src="/js/laughter.js"></script>
</body>
...

中间件的设置

其次,把 connect-cachify 库引入到你的 NodeJS 服务器中。建立你自己的 production 的开发资源映射并配置好中间件。

...
// Include connect-cachify
const cachify = require('connect-cachify');
  
// Create a map of production to development resources
var assets = {
  "/js/main.min.js": [
    '/js/lib/jquery.js',
    '/js/magick.js',
    '/js/laughter.js'
  ],
  "/css/dashboard.min.css": [
    '/css/reset.css',
    '/css/common.css',
    '/css/dashboard.css'
  ]
};
  
// Hook up the connect-cachify middleware
app.use(cachify.setup(assets, {
  root: __dirname,
  production: your_config['use_minified_assets'],
}));
...

为了保持代码清爽,asset 映射可以放到一个文件中,这样既可成为connect-cachify 的配置,也是你的程序的配置。

 
更新你的模板来使用cachify

最后,必须更新你的模板以指出使用到的 Javascript 和 CSS 在哪里。JavaScript 用 “cachify_js” 来指明,而 CSS 用 “cachify_css” 指明。

...
<head>
  <title>Dashboard: Hamsters of North America</title>
  <%- cachify_css('/css/dashboard.min.css') %>
</head>
<body>
  ...
  <%- cachify_js('/js/main.min.js') %>
</body>
...

!

Connect-cahified输出

如果将参数production设置为false,connect-cachify将输出三个link标签与三个script标签,与原来的输出一样。如果将production设置为true,将只输出各一个标签。各标签的url将被加上MD5 hash码前缀。而MD5 hash码前缀用于防止缓存。hash码将会随着产品资源文件内容发生变化,以清除缓存机制副作用。

<head>
  <title>Dashboard: Hamsters of North America</title>
  <linkrel="stylesheet"type="text/css"href="/v/2abdd020a6/css/dashboard.min.css"/>
</head>
<body>
  ...
  <scripttype="text/javascript"src="/v/acdd2ab372/js/main.min.js"></script>
</body>
...
以上便是connect-cachify的所有设置。
 

结论

有许多简单的方法来加快网站速度。利用3C技术-合并(concatenation)、压缩(compression)与缓存(caching)-将大大提高网站的下载速率与改善用户的使用体验。Connect-cachify通过合并与缓存显著改善NodeJS应用,但我们应该可以做的更好。在下一篇章节中,将介绍如何使用ETagify生成动态内容并尽可能的缓存资源。