前端性能优化笔记(1)代码资源篇

最近在学习关于前端优化的一些东西,做个笔记,供分享!

什么是优化的核心?

优化核心是网络请求,很多人在输入 url 请求资源的时候,耗费最多时间的反而是网速,用户网速不理想,那我们是不是能做点什么?

理解减少http请求数量和减少请求资源的两个大小要点!


web前端本身是一种GUI软件,本可以直接借鉴其他GUI系统架构设计方法,但web前端又有些特别,不一样。GUI软件使用的是CS架构,在安卓APK安装包的时候,就已经将GUI相关类型的一些文件保存在了本地,等用户下次访问的时候是本地资源。


BS架构(webserver)模式是将jsimgcss资源放在了服务器和CDN上,用户输入了url,这时候我们浏览器采取发出请求, 动态的,增量式的,去加载我们的静态资源,因为我们web前端去访问的过程实际上是一个动态的,增量式的加载静态资源的 一个过程,它是通过我们的http请求,通过浏览器,发送到我们的server进行返回,最终拿到我们的资源,如果在这个阶段,能更快的拿到资源,我们的接口返回的数据更快,那么实际来说,对用户的体验也就更好。

浏览器从发送请求到返回都发生了什么事情?

我们从中去找一些优化点,缩短http请求时间,从而提升速度 ,那么这样就要像一个问题,浏览器从发送请求到返回发生了什么?

1.用户输入url请求后,浏览器内部的核心代码会将这个url进行拆分解析domain,最终将这个domain发送到dns服务器进行查询,然后返回dnshost相对应的一个IP地址,然后将IP地址返回给浏览器,浏览器收到请求后就知道要把请求发送到哪个地方去,将IP打在协议中并且参数也跟随协议发送一个请求到网络中去。
2.经过局域网,交换机,路由器,主干网络最后到达服务端。
3.服务端是一个具有MVC架构的系统,首先会进入到Controller ,在controller中进行逻辑处理和请求的分发,然后会调用Model层,Model层是和数据进行交互的,过程中会去调用redisdbmysql等数据库调用数据,最后通过view层处理进行response,这么下来,一个从服务器端response就回到浏览器。
4.浏览器拿到后会进行render过程, 根据请求回来的html,以及这个html关联的cssjs进行一个渲染render树,DOM树以及对应的CSS树 ,然后将DOM树和CSS树进行一个整合,从而在页面进行一个样式的渲染。最后执行js脚本产生动态效果的能力,这就是整个浏览器请求的展现过程。

可以优化的点

1.dns可以做一个缓存。不用再到dns服务器解析。
2.网络请求涉及到带宽、缓存、网络的选择 ,很多公司选择了CDN,免去了缓存问题和选择网络的一个过程。但是有个问题,CDN是储存静态资源,我们本身请求静态资源的时候是会有一个cookie,这个是没用的,我们希望请求静态资源的时候讲cookiehttps请求的header中去掉。但是有很多时候CDN的域名和本身网站的域名相同。那么就会将一些cookie从我们主站的网络携带到CDN的服务端,这实际上是对网络无畏的损耗,所以CDN的域名尽量不要和主站一样。这样就能防止访问CDN还携带主站cookie的这个问题。
3.有些接口是没法用CDN的,对于这个是否能做一些缓存呢?实际上,除了CDN,我们还可以在浏览器本地做一些缓存的。
通过浏览器端的缓存策略, 我们对于一些相同的接口和相同的资源是可以去浏览器缓存中读取数据,这样的话,访问速度又得到了提升
4.除了缓存和路径选择,带宽也是重要的一点,一个http请求如果在带宽相对较小的话,返回的速度肯定相对会快一些的,所以减小http请求的大小也是很重要的一点,另外每一个http请求都会重网络环境达到服务器,实际上每次请求都是对网络的损耗,如果能将多次http请求合并成一次,从而减少网络的损耗。也是可以优化的一点。
5.现在大型框架,比如vuereact都是在浏览器中进行渲染的,首屏页面会有较大损耗,这是非常不利于前端性能优化的,所有才有SSR这类的服务端渲染方案,从而将html直出到浏览器端,而不是到浏览器端再渲染html

综合上述,可以知道,潜在的一些前端性能优化点

  1. dns是否可以通过缓存减少时间。
  2. 网络请求是否走的是最近的网络环境.
  3. 相同的静态资源是否被缓存。
  4. 能否减少 http 请求大小。
  5. 减少 http 请求。
  6. 服务端渲染。

掌握压缩和合并的原理

压缩无非就是减少资源文件的大小,合并是减少HTTP请求的数量。
google页面将换行和空格能减少的都删除了,而sina则没有.

什么是前端html压缩呢?

HTML本身是一种超文本的语言,本身在开发中,回车是能够帮助我们去理解、读取和分析代码结构的,但是在实际线上是没有太大作用,代码压缩就是压缩这些在文本文件中有意义,但是HTML不显示的字符,包括,空格,制表符,换行符等,还有一些其他意义的字符,如HTML注释也可以被压缩。

这是压缩前后的大小,压缩前后的对比真的不大吗?

以谷歌为例:
google的流量,占到整个互联网的40%2016年全球网路流量达到1.3ZB1ZB = 10^9TB),那么google2016年的流量就是1.3ZB*40%,如果google1MB请求减少一个字节,每年可以节省近500TB

如何进行html压缩?

掌握通过在线网站和fis3两种实现压缩和合并的方法

现在有很多网站提供htmlcssjs压缩,百度上一搜一堆。这个就不多说了
FIS3是一门面向前端的工程构建工具。解决前端工程中性能优化、资源加载(异步、同步、按需、预加载、依赖管理、合并、内嵌)、模块化开发、自动化工具、开发规范、代码部署等问题。压缩原理是通过正则和中间码的一些规则去进行源文件的分析,分析require语法及依赖,通过整体的依赖关系及语法的分析,建立依赖树,之后fis.compile(file)对单文件进行编译,所以fis3大体上分为两步,单文件的编译和打包的过程。

nodejs提供了html-minifier工具。

nodejs是一门很强大的js语言。可以在前端,服务端运行,vue-cli里也有基于它的工具搭建的压缩工具,在build目录下的webpack.prod.conf.js
webpack html压缩:
文件下

const HtmlWebpackPlugin = require('html-webpack-plugin')
new HtmlWebpackPlugin({//html压缩
filename: process.env.NODE_ENV === 'testing' ?
'index.html' :
config.build.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'
})

如何进行 css 压缩呢?
1.使用在线网站进行压缩。
2.使用html-minifierhtml中的css进行压缩。(html文件内的css
3.使用clean-css库对css进行压缩。
webpack css压缩:

const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
new OptimizeCSSPlugin({//css压缩
cssProcessorOptions: config.build.productionSourceMap ?
{ safe: true, map: { inline: false } } :
{ safe: true }
});

js压缩有哪些方面
1.删除无效字符。
2.剔除注释。
3.代码语义的缩减和优化,比如函数调用和封装…
4.代码保护,这也是对代码安全非常重要的一部分。将代码压缩至不可读、不可解析的程度,防止通过网站漏洞进行攻击。
js压缩和混乱的方式:
1.使用在线网站进行压缩。
2.使用html-minifierhtml中的js进行压缩。
3.使用uglifyjs2js进行压缩。
webpack js压缩:

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
new UglifyJsPlugin({//js压缩
uglifyOptions: {
compress: {
warnings: false
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),

文件合并

文件合并的优缺点

如图,左边是使用keep-alive但是不合并请求前的请求过程。当浏览器向服务器发起请求的时候,首先要建立连接,然后获取A的数据,服务器根据需求发送A.js给浏览器。浏览器之后再请求B的数据…. 这样的可能会导致严重的网络延迟和丢包。而合并请求后,一次连接,一次请求就解决了所有文件。
可以看出,不合并请求前会有以下缺点:
1.文件和文件之间有插入的上行请求,增加了N-1个网络延迟。
2.受丢包问题影响更严重。
3.keep-alive请求,经过代理服务器时可能断开,不能保证持续的keep-alive状态。
但是文件合并也存在一定的问题。
1.首屏渲染问题,比如我们在首页的 html渲染是依赖于众多资源文件中的某个js,而合并请求势必会让总体的js文件比以前大,再有某个js文件比较大的话,首屏渲染会等到最后所有文件下载完毕后再进行渲染。严重拖慢了首屏的体验。
2.缓存失效问题,现在的js是有缓存的,如果这个js有更新,加载资源的时候会给这个js文件名后加一个MD5戳,以此来判断文件是否已经改变。A.JSB.jsC.js合并后,A.js发生改变会导致整个缓存失效。需要重新加载,文件的不合并只有某个文件更新,而合并后存在着整体js缓存失效。

中和办法。

要想彻底解决目前是没办法的,鱼与熊掌不可兼得,那要怎么尽量去解决其中的问题呢?
1.公共库和业务库分开合并,平常开发项目中,公共库的改动是非常少的,而业务库的改动最为频繁。分开合并后,能够尽量的减少重新缓存的次数。
2.不同页面的合并,是针对于日常见到的单页应用,对于一个单页应用来说,在页面加载的时候,会请求当前单页应用所有的js文件,不是请求整个网站的js文件,这显然是不合理的,我们希望路由到当前页面的时候才去加载当前页面的js组件,而不是浏览A页面就已经进行下载BCD页面的js文件。对A页面的加载非常不利的,这一点对于目前的框架来说都有各自其实现的方式,例如vueresolve => require([‘xxx.vue’], resolve),angularloadChildren
3.真正的项目下会有不用的case,视情况而变吧,教程是死的,人是活的….
附上手动压缩的对比图,压缩前

压缩后

图片篇

jpg压缩过程

这个是jpeg图片压缩的整个过程,首先Raw Image Data=>Color Transform阶段会将jpeg的图片颜色空间转到rgb的颜色空间,然后下一阶段进行重采样,区分高频和低频的颜色变换,到Forward DCT过程将图片的高频颜色变换,采样的结果,进行一个压缩,这样压缩的收益才会比较大。Quantization将数据进行一个量化,Encoding编码,最后才拿到了压缩过后的jpg图片。

png8、png24、png32之间的区别

png8———256色,支持透明,因为png颜色本身就是一个索引,本身会自带药依赖的一些环境配置,png8之所以是256色是因为其内部有一个调色板,其中有256种颜色的索引,会建立一个颜色的索引表,支持2的8次方的颜色索引,但png8的颜色只会在这256种颜色中选择,所以不会有那么多的颜色供其选择,优点是只需要2^8次方(8-比特)的颜色索引就能够锁定一个颜色,文件会较小。
png24———2^24色,不支持透明,2的24次方,一个颜色就需要24-比特(长度也是png8的3倍长度),而且不支持透明。
png32———2^24色,支持透明,简单来说就是在png24的基础上增加了8位色,以此来支持png的透明。

业务场景

假如我们有一张大海,蓝天的图,这种颜色差别不会太大的图,我们使用png8位也能够展示图片信息。每种图片格式都有自己的特点,针对不同的业务场景选择不同的图片格式很重要。
jpg : 有损压缩,但是压缩率高,不支持透明。适合不需要透明的图片都可以采用。
png : 支持透明,浏览器兼容性好,并且有png8、png24、png32提供选择,针对不同图片选择色位数。适合需要透明图片的业务场景。
webp : 是2010年谷歌提出的一种图片格式,安卓已经支持,压缩程度更好,但是在ios Safari webview有兼容性的问题。适用于安卓全部。
svg矢量图 :是一种利用html标签绘制的图片,代码内嵌,相对较小,图片样式相对简单的场景,由于是一种矢量图,不会随着图片面积扩大而出现马赛克的现象,适用于图片样式相对简单(比如iconfont/fontawesome)的业务场景。
gif : 需要上动画就用它吧。

雪碧图。

雪碧图是将多张图片合并到一张透明的png图片上,运用background-position进行定位选择,减少了http请求次数,弊端是无法进行压缩,文件过大等原因。整个页面会依赖于这张图片的加载完成。目前facebook就是采用雪碧图的方式,中和方式就是将各组小型图片进行雪碧图合并。如果对雪碧图有不熟悉的,可以到spritecow网站工具辅助定位。

images inline

当一些过小的图片,比如icon存在于html中。十个0.1kb的icon真的要发出十次请求吗?耗费的过程不在于文件大小,而在于请求过程了,这显然是不合理的。我们需要将icon转换为base64位图片,存在于html的某个dom节点上,不需要其进行请求。

svg

使用svg进行矢量图的绘制,

<svg version="1.1" id="web-skill" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="160px" height="108px" viewBox="0 0 160 108" enable-background="new 0 0 160 108" xml:space="preserve">
<g id="mobile" style="transform: matrix(1, 0, 0, 1, 0, 0);">
<path fill="#FFFFFF" d="M49.1,102.4c0,1.2-1,2.1-2.1,2.1H20.6c-1.2,0-2.1-1-2.1-2.1v-56c0-1.2,1-2.1,2.1-2.1h26.3
c1.2,0,2.1,1,2.1,2.1v56H49.1z"></path>
<path fill="#00D9B3" d="M46.9,106H20.6c-2,0-3.6-1.6-3.6-3.6v-56c0-2,1.6-3.6,3.6-3.6h26.3c2,0,3.6,1.6,3.6,3.6v56
C50.6,104.4,48.9,106,46.9,106z M20.6,45.7c-0.3,0-0.6,0.3-0.6,0.6v56c0,0.4,0.3,0.6,0.6,0.6h26.3c0.4,0,0.6-0.3,0.6-0.6v-56
c0-0.4-0.3-0.6-0.6-0.6H20.6z"></path>
<path fill="#00D9B3" d="M35.9,97.2c0,1.2-1,2.1-2.1,2.1c-1.2,0-2.1-1-2.1-2.1c0-1.2,1-2.1,2.1-2.1C35,95,35.9,96,35.9,97.2"></path><path fill="#00D9B3" d="M35.4,76.5c2.3-0.8,3.9-2.9,3.9-5.4c0-3.2-2.6-5.7-5.7-5.7c-3.2,0-5.7,2.6-5.7,5.7v10.1
c0,0.5,0.4,0.9,0.9,0.9h10.1c0.4,0,0.7-0.2,0.8-0.5c0.1-0.3,0.1-0.7-0.2-1L35.4,76.5z M33.6,67.1c2.2,0,4,1.8,4,4
c0,2.1-1.6,3.8-3.6,4l-4.3-4.3C29.8,68.7,31.5,67.1,33.6,67.1 M29.6,80.3v-7.1l7.1,7.1H29.6z"></path>
</g>
<g id="desktop" style="transform: matrix(1, 0, 0, 1, 0, 0);">
<path fill="#FFFFFF" d="M128.6,77.6c0,1.7-1.3,3-3,3H46.5c-1.7,0-3-1.3-3-3V21.1c0-1.7,1.3-3,3-3h79.1c1.7,0,3,1.3,3,3V77.6z"></path>
<path fill="#00D9B3" d="M125.6,82.1H46.5c-2.5,0-4.5-2-4.5-4.5V21.1c0-2.5,2-4.5,4.5-4.5h79.1c2.5,0,4.5,2,4.5,4.5v56.5
C130.1,80.1,128.1,82.1,125.6,82.1z M46.5,19.6c-0.8,0-1.5,0.7-1.5,1.5v56.5c0,0.8,0.7,1.5,1.5,1.5h79.1c0.8,0,1.5-0.7,1.5-1.5
V21.1c0-0.8-0.7-1.5-1.5-1.5H46.5z"></path>
<path fill="#00D9B3" d="M101.8,106c-7.3,0-13.2-5.9-13.2-13.2V80.6c0-0.8,0.7-1.5,1.5-1.5c0.8,0,1.5,0.7,1.5,1.5v12.2
c0,5.6,4.6,10.2,10.2,10.2c0.8,0,1.5,0.7,1.5,1.5S102.7,106,101.8,106z"></path>
<path fill="#00D9B3" d="M70.2,106c-0.8,0-1.5-0.7-1.5-1.5s0.7-1.5,1.5-1.5c5.6,0,10.2-4.6,10.2-10.2V80.6c0-0.8,0.7-1.5,1.5-1.5
c0.8,0,1.5,0.7,1.5,1.5v12.2C83.4,100.1,77.5,106,70.2,106z"></path>
<path fill="#00D9B3" d="M88.6,53.8c3.6-1.2,6.2-4.6,6.2-8.6c0-5-4.1-9-9-9c-4.9,0-9,4.1-9,9v15.9c0,0.8,0.6,1.4,1.4,1.4H94
c0.6,0,1.1-0.3,1.3-0.8s0.1-1.1-0.3-1.5L88.6,53.8z M85.7,38.9c3.5,0,6.3,2.8,6.3,6.3c0,3.3-2.5,6-5.7,6.3l-6.8-6.8
C79.8,41.5,82.5,38.9,85.7,38.9 M79.5,59.7V48.5l11.2,11.2H79.5z"></path>
</g>
<g id="mobile2" opacity="0" style="transform: matrix(1, 0, 0, 1, 0, 0); opacity: 0;">
<path fill="#FFFFFF" d="M49.1,102.4c0,1.2-1,2.1-2.1,2.1H20.6c-1.2,0-2.1-1-2.1-2.1v-56c0-1.2,1-2.1,2.1-2.1h26.3
c1.2,0,2.1,1,2.1,2.1L49.1,102.4L49.1,102.4z"></path>
<path fill="#00D9B3" d="M46.9,106H20.6c-2,0-3.6-1.6-3.6-3.6v-56c0-2,1.6-3.6,3.6-3.6h26.3c2,0,3.6,1.6,3.6,3.6v56
C50.6,104.4,48.9,106,46.9,106z M20.6,45.7c-0.3,0-0.6,0.3-0.6,0.6v56c0,0.4,0.3,0.6,0.6,0.6h26.3c0.4,0,0.6-0.3,0.6-0.6v-56
c0-0.4-0.3-0.6-0.6-0.6H20.6z"></path>
<path fill="#00D9B3" d="M35.9,97.2c0,1.2-1,2.1-2.1,2.1c-1.2,0-2.1-1-2.1-2.1c0-1.2,1-2.1,2.1-2.1C35,95,35.9,96,35.9,97.2"></path><path fill="#00D9B3" d="M35.4,76.5c2.3-0.8,3.9-2.9,3.9-5.4c0-3.2-2.6-5.7-5.7-5.7c-3.2,0-5.7,2.6-5.7,5.7v10.1
c0,0.5,0.4,0.9,0.9,0.9h10.1c0.4,0,0.7-0.2,0.8-0.5c0.1-0.3,0.1-0.7-0.2-1L35.4,76.5z M33.6,67.1c2.2,0,4,1.8,4,4
c0,2.1-1.6,3.8-3.6,4l-4.3-4.3C29.8,68.7,31.5,67.1,33.6,67.1 M29.6,80.3v-7.1l7.1,7.1H29.6z"></path>
</g>
</svg>

效果图。

别以为这个很复杂,其实如果你了解SVG语法的话,你会觉得很简单,这仅仅利用的path画点画线而已。
第三方矢量图库,例如iconfontfontawesome。在业务场景中是经常使用的。引进当前项目的iconfont.css,行内标签使用<code class=”codes“><i class=”iconfont icon-xxx“></i></code>进行使用。

WebP

优势体现在它具有更优的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量,同时具备了有损和无损的压缩模式,alpha透明以及动画的特性,在jpeg和png上的转换效都非常优秀、稳定和统一。
智图是一个将jpg.png图片转换成webp的在线网站.

推荐一个网站:www.tinypng.com 是对png、jpeg图片进行在线压缩的网站。将图片内高频的色位bit压缩成低频。png32降至png24、png8。达到压缩的目的。特别是对于颜色样式简单的图片来说。