之前看到一句话,在这个计算机快速发展的时代里,想要不被计算机代替,就不要像计算机一样去思考。一直不是很懂这句话是什么道理,直到发现工作到了瓶颈的时候。
作为一个前端工程师,在很多人眼里就是个写写页面的,或者说稍微懂点我们这个行业的人会说:哦,还能跟后端做做交互。但是,工作久了就发现,好像前端的存在感怎么越来越弱了呢。前端这个行业的门槛很低,基本上你只要稍微懂点电脑,花个半个月速成一下,写几个前端页面完全没有问题。还有就是好多学美工的,他们想要发展,也会学点前端的知识。这样,好像美工都已经能代替前端了。还记得前几天我们市场总监问我,你们做前端的除了写页面还会干啥,能做美工的吗。这个问的我一时词穷,完全不知道该怎么回答...那时候我好想说一句,对不起,我是写代码的,不是搞设计的,请尊重我的职业。哈哈,当然这里完全没有看不上设计的意思,纯粹是我对设计并没有这么好的天赋而已。其次,就是公司的技术总监,完完全全的就是个全栈工程师,因为是创业公司,在我来之前,前后端完全就是他一个人搞定的。这么下来,我发现我纯在的必要就更低了,这不是谁都能写页面吗,还要前端干什么。然而,这样理解对于前端来说太片面跟太局限了。前端怎么可能只是写写页面呢?这是二十年前的前端干的活,实现页面什么的。现在的前端已经远远不是写个页面这么简单了。我们还要考虑页面如何布局,怎样给用户最好的体验,怎样让搜索引擎更容易搜索到我们网站。还有就是现在前端各式各样的框架,合适框架能大大提升我们网站的性能,而不合适框架却只能拖慢网站的加载速度。
好了,说了这么多,该说说重点了。我刚刚做前端的时候对前端的理解也很浅,就觉得只要能实现页面就可以了,所以对网站加载速度什么的并没有太大的关注。最后网站完成了,发现加载个页面至少要个七八秒。。。说实在的,这个七八秒可以赶跑绝大部分的用户了,一般用户来说,在网站的停留时间页面两到三秒,如果在这个时间内网页不能加载出来的话,用户基本都会选择关闭网站。所以说,网站性能优化是很有必要的。在网上看了很多关于性能优化的东西,都是一段一段的,不能系统的学习,后来买了本o'reilly系列的网站性能优化的书,里面写的非常详细,这里,我就要说说他其中的一章性能优化之减少HTTP请求。
在我们去访问一个新的网站的时候,我们在地址栏输入了一个地址,去请求某个服务器下的文件,然后服务器接收到请求之后,又给我们返回了一个HTML文档和对应的CSS,JS,img文件,而每一个文件,就是一个HTTP请求。打开我们的开发者工具,点击Network我们可以看到,在加载一个新的页面的时候,下载HTML文档只占下载所有文档时间的不到20%,大部分都是在10%以下,反而是加载页面其他文件占据了大部分的加载时间。尤其对于一些多图片的网站来说,图片的加载占据的大部分的性能。这里不得不提到网站性能优化书中提到的一条黄金法则:只有10%~20%的用户的最终响应时间花在了下载HTML文档上。其余的80%~90%的时间都花在了下载页面中的所有组件上。这里的组件,指的就是JS,CSS,image这些文件。所以,要提示网站性能,就要减少这些组件,从而减少HTTP请求次数。而在这些组件中,最多的其实就是图片文件,所以要提示网站性能之一,就是要减少图片的请求次数。那要怎么减少图片请求次数呢?
首先,我们可以使用图片地图(Image Maps)。图片地图,第一次看到这个词的时候可能会想到是不是跟地图一样的图片,其实不然。图片地图其实就是给用户展示一张图片,然后用户点击这张图片不同位置的时候,会产生不同的效果。下面就是图片地图的使用方法,就是在img标签中使用一个属性,uesmap属性指向map标签的name属性。map中的area属性则是显示不同的区域的大小,当shape为rect也就是正方形时,coords的前两个值表示起始位置,后两个值表示结束位置。
<img usemap="#map1" border=0 src="/images/imagemap.gif?t=1490671322"> <map name="map1"> <area shape="rect" coords="0,0,31,31" href="javascript:alert('Home')" title="Home"> <area shape="rect" coords="36,0,66,31" href="javascript:alert('Gifts')" title="Gifts"> <area shape="rect" coords="71,0,101,31" href="javascript:alert('Cart')" title="Cart"> <area shape="rect" coords="106,0,136,31" href="javascript:alert('Settings')" title="Settings"> <area shape="rect" coords="141,0,171,31" href="javascript:alert('Help')" title="Help"> </map>
我们也可以直接访问性能优化书提供给我们的体验地址http://stevesouders.com/examples/imagemap.php。
跟这个相对应的是最普通的每一个按钮都用不同小图片的案例的体验地址http://stevesouders.com/examples/imagemap-no.php。
然后我们把浏览器限速开成最大的限速,我用的是google浏览器,打开开发者工具,在Network下会有一个No throttling,点击一下,可以看到最慢的是GPRS,设置了之后,使用了图片地图的例子平均加载耗时为2000ms,而没有使用图片地图的例子平均加载耗时为4000ms,这里我们可以看到,使用了图片地图的速度提升了进一倍。
不过,虽然图片地图在性能优化上有很大的提高,但是使用的并不是很普遍,主要在于他有局限性,首先就是他定义的图片地图上的区域坐标时,如果使用手工的方式很难完成并且容易出错,而且他处理矩形外基本上无法定义其他形状。而通过DHTML创建的图片地图则在IE中无法工作。因为这些方面的原因,图片地图的使用量并不大,但有没有其他方法呢?当然有,跟图片地图很类似的,还有一种方法叫做CSS Sprite,人们平时喜欢叫他精灵图或者雪碧图,他的原理也是把小图标之类的整合成一张图片,但不同的是,他是使用背景图的方式。
CSS Sprite的实现原理也很简单,先给一个固定宽高的盒子,然后给他设置背景图,然后通过调整背景图的大小和位置,从而来显示我们小图片。代码如下:
<style> #navbar span { width:31px; height:31px; display:inline; float:left; background-image:url(/images/spritebg.gif?t=1490672913); } .home { background-position:0 0; margin-right:4px; margin-left: 4px;} .gifts { background-position:-32px 0; margin-right:4px;} .cart { background-position:-64px 0; margin-right:4px;} .settings { background-position:-96px 0; margin-right:4px;} .help { background-position:-128px 0; margin-right:0px;} </style> <div id="navbar" style="background-color: #F4F5EB; border: 2px ridge #333; width: 180px; height: 32px; padding: 4px 0 4px 0;"> <a href="javascript:alert('Home')" title="Home"><span class="home"></span></a> <a href="javascript:alert('Gifts')" title="Gifts"><span class="gifts"></span></a> <a href="javascript:alert('Cart')" title="Cart"><span class="cart"></span></a> <a href="javascript:alert('Settings')" title="Settings"><span class="settings"></span></a> <a href="javascript:alert('Help')" title="Help"><span class="help"></span></a> </div>
对应的案例地址http://stevesouders.com/examples/sprites.php,同样把限速调到最高,我们发现他所消耗的时间跟图片地图的时间差不多,也是在2000ms左右,而且他有一个好处,就是不需要连续的图片。我们只需展示其中的一部分就好了。如果一个页面中有很多这样的小按钮,图标之类的图片的时候,CSS Sprite绝对是一个很好的解决方案。
除了CSS Sprite和图片地图之外,还有一种能减少图片HTTP请求的方式就是使用内联图片(Inline images),就是通过使用data:URL的模式,我们最熟悉的就是把图片转成base64的格式,说白了,就是把一张图片转化成了一长串数据,浏览器在解析的时候会把这数据解析成图片。代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<a href="javascript:alert('Help')" title="Help"><img border=0 src="data:image/gif;base64,R0lGODlhHwAfAPcAAAAAALW1tb2MhL2UhL29tcaUlMbGvc6UWs7OxtZ7ANalY9ata9bWztbW1tbe1t7e1uelGOfn1ufn3ufn5+fv3u+MAO+9Ie/v3u/v5+/v7/fOMff35/f37//nYyH5BAEAAAAALAAAAAAfAB8AAAj+AAEIHEgQAwMDARImNMAAA8GHEAdKMEAAgQMMGDFIcICgooSIETEgYJhxAgaTGE0eROAQpMCJCCScnGmyJs2RH0FKINCQ5syfNg0SyPkQA8mgSIGePNiSIIKYNSVMkClV6smqVyc8fbhzgtevXguIHVtAKtipQwcaZSChrVsJBRZo6GChroKyb9syfTn0gYQHfh8IWGDhwAABCuwK+BvYb1qDBgBLBjzAgoLFDgYktiDAwWTAJNc6GE3agQDOpQVAgDCgNGmmGAIwcMBgMgMBAgbMFqxgdefPDxgEwCh7NoPax2kbF3Bg9QEBx5EffxBAZnHj05Pfbg7hOXbtwq3YR/+u/LbzztHL064eO7375KoTQCefnn1F9e/jz6fPYCTGkcYpJ+Btuc03oHEGsITBAwQMSNuD4EEoIQMEPJBRgoDVFlyGguEG3YMc9meATAAINZtnu+0mQAUJtDZacCg6wFNLGhlggGulDaDjbyeSZiOJAi1YEXCSeUbkAx1ZWBSFMXnG2EZ+Oekkkg02pZZQI/7Vll9adukARQ4AWRQGX/K05ZldjnSjmBBhRBsBBKz51kFwzoaRS2r91R8BCiUUp5NW4lmiRhuNN1pbdwraZkYaMRroQwEBADs="></a>
案例地址为:http://stevesouders.com/examples/inline-images.php,限速后响应时间为1500ms左右。
但是当我们把内联图片的放在HTML中的时候,他就不能缓存了,尤其是公司logo之类的时候,他就不能缓存,这时候我们就可以把图片写在css中,利用css的缓存来实现图片的缓存。
案例地址为:http://stevesouders.com/examples/inline-css-images.php,限速后响应时间为2500ms左右。
总的来说,对于页面太多小图片,小按钮,小图标的处理,CSS Sprite最为推荐的,首先就是简单易操作,而且性能也非常好。
除了优化图片之外,还有css和js文件的优化,在理想的情况下,最好是只有一个css和一个js,但实际开发中,很多情况下我们都会引入狠多外部的文件,又或者是为了模块化开发考虑,把js分成了很多个文件。对于这个问题的解决办法,就是抽取js代码中有用的代码,然后整合到一个文件中,不过这种方法对于模块化开发的人来说是一种倒退。解决的方法是遵守编译型语言的模式,保持JavaScript的模块化,而在生成过程中从一组特定的模块生成一个目标文件。这么说可能有点复杂,简单来说,就是在写代码的时候用模块化开发的思想,而在实际上线的版本中,则选择其中有用的代码上线并且合并。