如今许多公司每每注重后端优化,而忽略了前端优化javascript
想一想若是辛苦优化了服务器,后台,排查了sql
却在最后页面加载展现的时候很慢,也得不偿失css
其实,先后台优化都是相辅相成的
后台优化好了,响应请求速度快,前台展现的更迅速
前台优化了没必要要的请求,后台压力也会更小html
一直想静下心来写一篇博文,
无奈心浮气躁,不得安定,断断续续一直写到今天....
那么如今就来和你们分享一下个人前端优化经验吧前端
大纲:html5
请求优化
首先咱们来优化HTTP请求数
因为用户浏览的,每每只是局部网页,
因此只加载用户可视范围内的资源,就会减小一些没必要要的请求,也会减小浏览器加载资源的消耗
考虑到移动端可视范围,网络流量,性能,延迟加载做用尤其明显
适合延迟加载的东西不少,最须要的固然是图片,这里推荐lazyload
https://github.com/tuupola/jquery_lazyload
图片延迟加载的原理就首先将要延迟加载的图片src替换为空白图片或者参数指定的loading图
而后根据当前元素的位置(offset)来判断是否在页面可视范围(页面宽/高度+滚动宽/高度)
若是在,就将真实图片资源路径替换回src让浏览器加载
防止浏览器解析到HTML中<img>标签的src属性就开始下载资源,最好将原<img>的src属性去掉
统一配置lazyload的参数去加载loading图吧,如咱们项目中这样:
$(".main_content img").lazyload({ placeholder: "/images/loading.gif", threshold:200 });
再来看到lazyload的源代码,可视范围判断上下左右,写的十分完善
$.belowthefold = function(element, settings) { var fold; if (settings.container === undefined || settings.container === window) { fold = (window.innerHeight ? window.innerHeight : $window.height()) + $window.scrollTop(); } else { fold = $(settings.container).offset().top + $(settings.container).height(); } return fold <= $(element).offset().top - settings.threshold; }; $.rightoffold = function(element, settings) { var fold; if (settings.container === undefined || settings.container === window) { fold = $window.width() + $window.scrollLeft(); } else { fold = $(settings.container).offset().left + $(settings.container).width(); } return fold <= $(element).offset().left - settings.threshold; }; $.abovethetop = function(element, settings) { var fold; if (settings.container === undefined || settings.container === window) { fold = $window.scrollTop(); } else { fold = $(settings.container).offset().top; } return fold >= $(element).offset().top + settings.threshold + $(element).height(); }; $.leftofbegin = function(element, settings) { var fold; if (settings.container === undefined || settings.container === window) { fold = $window.scrollLeft(); } else { fold = $(settings.container).offset().left; } return fold >= $(element).offset().left + settings.threshold + $(element).width(); }; $.inviewport = function(element, settings) { return !$.rightoffold(element, settings) && !$.leftofbegin(element, settings) && !$.belowthefold(element, settings) && !$.abovethetop(element, settings); };
关于图片这里,除了延迟加载外,用户上传的图片以及咱们所用的资源图片都应该进行压缩处理
如须要进一步提升压缩率,可使用例如:google开发的webp图片格式等..
不过不是全部浏览器都支持webp格式,须要针对浏览器响应
根据上面这段代码,其实咱们就能够延迟加载其余内容了,
总之呢,这里咱们的目的就是尽可能减小没必要要的请求
好比如今用的不少的下拉式翻页,就是判断到页面底部以后再ajax获取下页内容
若是考虑到网页只是局部更新的话,那使用ajax是很合适的
好处显而易见,无需从新请求整页,小巧快速,网页展现也友好一些
善用ajax对前端性能,体验都是有改善的
可是也要考虑到对搜索引擎的友好,
若是页面总体功能改变了,或者页面改动量大就要进行取舍了。
延迟加载的目的就是减小没必要要的请求,在用户有需求时才请求资源
因此对于用户来讲,实际上是有一点点“等待”的过程的
通常会用loading图,等待文字来改善这里的用户体验
可是有一些需求是但愿尽可能少出现这种“等待”过程的
这里咱们就能够预加载资源,以下,咱们先在js中加载图片
var img = new Image(); img.src="test.png";
提早加载好了图片,用户进行下一步时,图片则是从浏览器缓存中获取
多页数据也能够相似处理,页面初始能够默认加载两页数据
翻到第二页时,就ajax去获取第三页内容
翻到第三页时,就去获取第四页内容......
老是提早预加载一页数据
如此可必定程度上减小一些等待的过程
总的来讲延迟加载是尽可能少加载资源,预加载则是判断可能要的资源,尽可能去提早多加载,
都是为了优化用户的体验,适用于不一样场景
资源优化
网页中有些资源能够经过延迟加载等方式减小没必要要的请求
而许多的javascript脚本,css样式等资源倒是网页中必需要加载的
既然不可避免须要加载,那接着,咱们就能够去优化这些资源
首先咱们能够优化资源文件的大小,资源文件变小了,传输速度固然也快了
这里咱们压缩分为以下两种:
以下,在IIS7内启用Gzip压缩
能够看到,设置了以后资源的HTTP响应多了Content-Encoding:gzip
咱们写js代码,css,都命名尽可能取得有意义,多换行,tab把格式弄的优美
都是为了方便维护,再阅读,而机器解析咱们的代码的时候可无论这些。
这里压缩我推荐 uglify-js和 clean-css,都在nodejs环境下
这里可见压缩效果仍是很显著的,按我目前代码习惯,平都可以压缩一半左右
可是,不可避免,咱们在平常开发,发布的时候,会增长额外的工做量
这里我分享一下个人用法:
为了方便开发,我在项目中仍是引用的原文件
只是在生成发布文件后,执行下面bat批处理脚本
把发布文件夹内的js代码进行压缩,同名覆盖原文件,这样就不用修改项目内js引用地址
@echo off :: 设置压缩JS文件的根目录,脚本会自动按树层次查找和压缩全部的JS SET JSFOLDER=D:\project\scripts echo 正在查找JS文件 chdir /d %JSFOLDER% for /r . %%a in (*.js) do ( @echo 正在压缩 %%~a ... uglifyjs %%~fa -mangle -o %%~fa ) echo 完成! pause & exit
(*这个bat批处理脚本不是我写的,是之前在网上搜来的)
固然,用这种bat批处理脚本只知足一些小需求,咱们还能够用自动化构建工具来生成
这里我推荐gulp,一样在nodejs环境下,这里分享一个我本身写的静态资源压缩生成后缀的gulpjs
装好gulp以后,须要安装gulp的插件gulp-clean-css,gulp-uglify,gulp-rev,gulp-rev-collector以及gulp-sync
还有这个gulp-bom,我以前处理完以后,总是有乱码,发现生成的文件虽然是utf-8 却不是utf-b+bom,因此须要再处理一下
var gulp = require('gulp'), config = require('./config'), cleancss = require("gulp-clean-css"), uglifyjs = require("gulp-uglify"), rename = require("gulp-rename"), rev = require("gulp-rev"), revCollector = require("gulp-rev-collector"), del = require("del"), sync = require("gulp-sync")(gulp), bom=require("gulp-bom") ; //生成后缀 gulp.task("addv_css", function () { return gulp.src(config.css.src) .pipe(rev()) .pipe(gulp.dest(config.css.dest)) .pipe(rev.manifest()) .pipe(bom()) .pipe(gulp.dest(config.css.rev)); }); gulp.task("addv_js", function () { return gulp.src(config.js.src) .pipe(rev()) .pipe(gulp.dest(config.js.dest)) .pipe(rev.manifest()) .pipe(bom()) .pipe(gulp.dest(config.js.rev)); }); //更改cshtml中的 style引用 gulp.task("changev_css", function () { return gulp.src(config.rev.csssrc) .pipe(revCollector({ replaceReved: true })) .pipe(bom()) .pipe(gulp.dest(config.rev.dest)); }); //更改cshtml中的 js引用 gulp.task("changev_js", function () { return gulp.src(config.rev.jssrc) .pipe(revCollector({ replaceReved: true })) .pipe(bom()) .pipe(gulp.dest(config.rev.dest)); }); //压缩css gulp.task("cleancss", function () { return gulp.src(config.css.cleansrc) .pipe(cleancss()) .pipe(bom()) .pipe(gulp.dest(config.css.dest)); }); //压缩js gulp.task("uglify", function () { return gulp.src(config.js.uglifysrc) .pipe(uglifyjs({ mangle: true, define: true })) .pipe(bom()) .pipe(gulp.dest(config.js.dest)); }); gulp.task("default", sync.sync([["addv_css", "addv_js"], "changev_css", "changev_js", ["cleancss", "uglify"]]));
咱们项目内每每会引用多个javascript脚本,和多个css样式文件
因此能够把多个脚本合并到一个js文件内,而后统一引用它就能减小http请求
这里uglify-js和 clean-css 都支持多个文件合并压缩输出
>uglifyjs js1.js js2.js -m -o merge.js
>cleancss -o megar.css style1.css style2.css
也能够在服务器内合并输出,好比咱们看淘宝的合并:
<script src="//g.alicdn.com/kissy/k/6.2.4/??node-min.js,node-base-min.js,dom-base-min.js,query-selector-base-min.js,dom-extra-min.js,node-event-min.js,event-dom-base-min.js,event-base-min.js,event-dom-extra-min.js,event-gesture-min.js,event-touch-min.js,node-anim-min.js,anim-transition-min.js,anim-base-min.js,promise-min.js,base-min.js,attribute-min.js,event-custom-min.js,json-base-min.js,event-min.js,io-min.js,io-extra-min.js,io-base-min.js,io-form-min.js,cookie-min.js"></script>
他们则是在web服务器内作了处理,请求多个文件,会自动合并
有条件的同窗也能够这样进行合并
图片合并目的也是减小http请求,将页面中须要的相关图片合并到一张大图片里
而后用css的background-position定位到大图的具体局部位置
好比这样:
可是近年来好像用的愈来愈少了
想一想缘由,应该是。。。。维护起来[太麻烦]了
只要稍微改动一张图片,尤为是改变了大小的话,整个大图片都要改
而且还要把css样式也改个遍
不然就是继续往大图片里拼,无效的老图保留,致使图片愈来愈臃肿
再有,若是只是一些这样的小图标的话,用fonticon要方便得多
iconfont就是图标字体,将图标输出为矢量的字体
使用起来很是方便,对应字体的编码,就和网页中的普通文字同样
<i class="icon iconfont">U</i>
它对比合并的图片来讲
体积会更小,而且能用css控制大小,颜色
而后它仍是矢量的,放大也不失真
虽然iconfont制做,维护成本也不低,引用起来为兼容浏览器得引用多种格式
但好在如今用的人多,网上也有许多免费图标库供使用
好比这里阿里巴巴图标库
引用css放在<head>内,引用js放在</body>结束标签前,如今不少朋友都会这么作了
css加载是异步的,更早的加载出样式就能更早呈现出页面
js放在尾部,防止浏览器加载js而阻塞页面,形成页面“白屏”现象
若是有条件的话,咱们还能够启用额外的服务器,域名来存放资源
这样能减小主域名的HTTP请求数,让主服务器更快响应请求
还能减小主域名的cookie请求
缓存
说到缓存,首先想到的确定是服务器后台的缓存
其实,打开咱们的浏览器工具看一下,就会发现,网页前台也存在着许多缓存
它无声无息,悄悄优化着每一次访问
直接看响应头,咱们会发现这些字段:
Expires:Thu, 20 Oct 2016 06:43:43 GMT //告诉浏览器此日期之前可使用缓存文件
Cache-Control:public, max-age=3600 //表示资源在3600毫秒以内可使用缓存文件,若是和Expires同时存在则覆盖Expires
Last-Modified:Wed, 13 Jul 2015 08:52:12 GMT//配合Cache-Controls使用,标示资源的最后修改日期
ETag:5384183131862232576//配合Cache-Controls使用,标示资源由服务器生成的惟一标识(某些资源最后修改日期不可靠,或者不但愿展现最后修改日期,就可使用ETag)
上面这些都是控制前端缓存的字段,而后再来看看下面的HTTP状态码
//200 OK 请求已成功,请求所但愿的响应头或数据体将随此响应返回。
//304 Not Modified 请求资源没有改变,可使用缓存资源
因此这里当咱们第一次访问的时候,获得响应资源及缓存策略,
以后若是缓存有效,资源就会来自缓存
若是缓存无效了,就会判断是否有Last-Modified或者ETag,有则发送If-Modified-Since或If-None-Match请求头
服务器若是判断资源无修改,就会返回304,有修改就会返回200以及新的缓存策略
固然,这里只是指用户的普通操做,如:地址栏回车,页面连接跳转,新窗口,前进后退
若是用户是进行 刷新 操做,则不会读取缓存资源了,可是若是有Last-Modified或者ETag,依然会发送If-Modified-Since或If-None-Match请求头
若是用户是进行 强制刷新(ctrl+f5) 操做,那全部缓存策略都失效,会从新请求
可见,咱们每每只有第一次请求的时候,才会有较多的资源加载
因此咱们上面作了这么多优化,延迟加载,资源压缩,合并等等,
都是为了用户第一次访问的时候尽可能友好。
那么Cache-Control要如何在服务器设置呢,其实针对静态资源来讲
大部分服务器都会默认就将Cache-Control设置好了的,咱们能够视状况修改一些时效参数等等
咱们这里要注意的是用url去控制缓存的有效性
以下:
虽然它们请求的都是服务器上的同一个js文件,可是浏览器不会把它们看成同一个资源
能够看到v=1.01.js的请求是来源于cache
其余几个请求都是新请求
因此,咱们每次发布均可以修改资源url强制让用户页面上的缓存失效
这样用户不须要刷新也能获得最新的资源
离线存储在我以前一篇文章里也提到过,在移动端应用的比较多
它和缓存不一样,它设置好了以后,连离线也能访问,不管用户刷新或者新窗口,连接等等
使用manifest
<html manifest="/mobile.manifest">
在html上添加manifest,其中文件格式内容如:
CACHE MANIFEST ##须要离线的内容 CACHE: Script/jquery.js Script/gameconfig.js Image/home.png Image/logo.png ##老是访问网络的内容 NETWORK: * ##访问A失败时访问B FALLBACK
浏览器将缓存chache内全部的内容,而且能够离线访问,只要文件发生任何改变都将会从新读取并刷新所有缓存,因此更改注释是个更新缓存的好方法
这里要注意的是
1,添加了manifest的当前网页也会被缓存 因此推荐的方式是页面缓存,页面动态内容所有用ajax获取,因此在移动网站项目设计开始就要注意这个问题
2,页面中添加iframe 而后子页面引用manifest想达到缓存资源而不缓存当前页面内容,是无效的。
本地存储数据一直是网页端的弱项,在没有HTML5的localStorage前,用cookie能够保存一点数据
但付出的代价很大,cookie能保存的数据不多,而且它会伴随着每一次请求一块儿发送
localStorage就好多了,默认5MB的大小,除非用户手动清除,不然一直不过时,就连IE8浏览器都支持
这里要注意,localStorage和cookie同样受到跨域的限制
可使用domain控制
document.domain="";
其它的
在js中,咱们实现动画,就是利用定时器循环改变dom元素的属性来达到动画效果
可是许多属性更改以后会形成浏览器重绘,增长性能消耗
固然浏览器更新换代也作了许多优化,咱们优化js,css减小重绘,也能改进动画性能
可是想想,究竟应不该该让js去实现页面动画呢?
css3就是往这方面发展,让js更纯粹的去实现业务逻辑
页面效果之类的事情就让css去作吧
而且css3在动画效率上面也有加强,浏览器会单独处理css3动画,不占用js主线程,还能够硬件加速
未来还有提高的可能,因此快把咱们的js动画替换为css3吧!
一样更迭的还有flash,当初flash是为了弥补网页展示的不足而出现的“插件”
而如今网页标准一次次升级,html5的出现,再加上flash自身也有各类漏洞,性能问题
尤为是如今flash在移动端的支持不多,都加快了咱们替换flash的步伐
写到这里快写完了,忽然发现好像本身在啰啰嗦嗦了一整页。。
却又感受哪里漏都了一些,好吧,但愿你们不要嫌烦,若是都了解了,就当温习吧
若有纰漏,欢迎提醒
哦,还有些想说的
优化必定要选择适合本身项目,硬件条件的优化方式,千万不要盲目硬搬
还有要持续不断的关注新标准,方法,一直保持活力!