美文网首页
网站性能优化篇

网站性能优化篇

作者: 冰Q | 来源:发表于2017-08-31 14:27 被阅读986次

    (整篇基于网上内容整合及个人日常开发实践整理而成,如有雷同,纯属巧合)

    网站的访问量及用户的持久性其实在一定程度上取决于其性能,如果一个网站响应耗时久,动画卡顿,占用大量的cpu等,往往就会导致用户流失。尤其是app及微信端应用,可以这么说,如果页面打开都要超过4秒,这体验绝对差。作为一个开发者,是不允许出现这种情况的,那么该如何提高页面的性能呢?

    其实,大致的网站优化性能步骤不外乎减少HTTP请求次数,减少DNS访问,减少对DOM的操作,缩减请求的文件大小/cookie大小等等,如果你连上面都不清楚的,可以先移步去看看一个网站整体优化的具体从哪些方面入手,本人在该系列中,主要集中的是一些具体的实现方案。

    一.网站图片可从三个方面入手

    1. 压缩图片:

    1) 缩小图片分辨率: 尽量不要在页面中使用控制图片大小的方法来显示实际效果

    2) 改变图片格式并保持其质量: 如webP格式,一种支持有损压缩和无损压缩的图片文件格式,派生自图像编码格式 VP8。

    3) 工具有: https://tinypng.com/ , http://zhitu.tencent.com/ , https://isparta.github.io/

    4) 值得注意的是,webP作为google推广的一种图片格式,其兼容性还是受到很大的限制,

    若使用场景是浏览器,

    JavaScript 能力检测,对支持 WebP 的用户输出 WebP 图片

    使用 WebP 支持插件:WebPJS ( https://webpjs.appspot.com/ )

    若使用场景是 App,

    Android 4.0 以下 WebP 解析库(https://github.com/alexey-pelykh/webp-android-backport)

    iOS WebP 解析库(https://github.com/carsonmcdonald/WebP-iOS-example)

    2. 使用图片Sprite技术,即将多张小图标合并成一张大的图片,工具: css sprite或者ps

    3. base64加密压缩图片,不发送http请求: base64其实就是将图片格式编码成一串字符串,这样虽然减少了http请求,但还是会增大css文件的体积,从而增加生成cssDOM的耗时,因此,只 适用于极小或者极简单图片。(可使用webpack转化或者base64转化工具http://www.pjhome.net/web/html5/encodeDataUrl.htm )

    二 压缩及合并js/css文件,建议采用前端工具实现

    // 如使用gulp实现

    var gulp = require("gulp");

    var uglify = require('gulp-uglify');

    var minifycss = require('gulp-minify-css');

    var htmlmin = require('gulp-htmlmin');

    var gutil = require('gulp-util'); // 用来打印错误日志

    var imagemin = require('gulp-imagemin');

    var pngquant = require('imagemin-pngquant');

    var smushit = require('gulp-smushit');

    var babel = require('gulp-babel');

    var pump = require('pump');

    var autoprefixer = require('gulp-autoprefixer');

    //压缩html(html压缩后不知为何样式不起作用了,有待研究)

    // gulp.task('html', function(){

    //      gulp.src('./views/**/*.html')

    //          .pipe(htmlmin({

    //            collapseWhitespace: true, // 清除空格,压缩html

    //            // removeComments: true, // 清除html中注释的部分

    //            // minifyJS: true, // 压缩html中的javascript代码

    //            // minifyCSS: true // 压缩html中的css代码

    //          }))

    //          .pipe(gulp.dest('./static/views'));

    // });

    // 压缩图片(使用cache只压缩改变的图片,如发生修改文件名则需要清缓存,否则会有bug)

    //(实测,使用以下两种插件压缩jpg效果不明显,建议更换成gulp-tinypng,需注册拿key,每月限免500张)

    gulp.task('imagemin', function () {

             gulp.src('./public/**/*.{jpg,gif,ico}')

                    .pipe(imagemin(

                         [

                           imagemin.gifsicle({interlaced: true}),

                           imagemin.jpegtran({progressive: true}),

                           imagemin.optipng({optimizationLevel: 5}),

                           imagemin.svgo({plugins: [{removeViewBox: true}]})

                       ],

                      {

                          verbose: true

                      }

                ))

               .pipe(gulp.dest('./static/static'));

    });

    gulp.task('smushit', function () {

            gulp.src('./public/**/*.png')

                   .pipe(smushit({

                         verbose: true

                   }))

                 .pipe(gulp.dest('./static/static'));

    });

    // 压缩js文件

    gulp.task("uglify", function(cb) {

             pump([

                  gulp.src('./public/**/*.js'),

                 babel({

                      presets: ['es2015']

                 }),

                uglify({

                       // mangle: false,//类型:Boolean 默认:true 是否修改变量名

                       mangle: {

                      reserved: ['require' ,'exports' ,'module' ,'$']

                      } //保留关键字,新版不支持except

                 }),

                gulp.dest('./static/static')

            ],

           cb

           );

    });

    // 添加前缀/压缩css文件

    gulp.task('minifycss', function () {

            gulp.src('./public/**/*.css')    //需要操作的文件

            // .pipe(rename({suffix: '.min'}))  //rename压缩后的文件名

           .pipe(autoprefixer({

                      browsers: ['last 2 versions', 'safari >= 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6',   'android >= 4'],

                     cascade: true, //是否美化属性值 默认:true

                     remove:true //是否去掉不必要的前缀 默认:true

            }))

           .pipe(minifycss())  //执行压缩

           .on('error', function (err) { gutil.log(gutil.colors.red('[Error]'), err.toString()); })

            .pipe(gulp.dest('./static/static'));  //输出文件夹

    });

    // 拷贝剩余不用处理的文件

    gulp.task("copy1", function() {

             gulp.src(["./public/**", "!./public/**/*.{jpg,gif,ico,js,css,scss}"])

                    .pipe(gulp.dest("./static/static"))

    })

    // gulp.task("copy2", function() {

    //    gulp.src(["./views/**", "!./views/**/*.html"])

    //        .pipe(gulp.dest("./static/views"))

    // })

    // 监看文件变动

    gulp.task('watch', function() {

            // 看守所有.html

           //  gulp.watch('./public/**/*.css', ['minifycss']);

           // 看守所有.css

            gulp.watch('./public/**/*.css', ['minifycss']);

            // 看守所有.js

            gulp.watch('./public/**/*.js', ['uglify']);

            // 看守所有图片档

            gulp.watch('./public/**/*.{png,jpg,gif,ico}', ['imagemin', "smushit"]);

    });

    // 使用 gulp.task('default') 定义默认任务

    // 在命令行使用 gulp 启动 script 任务和 auto 任务

    gulp.task("default", ["imagemin", "smushit", "uglify", "minifycss", "copy1", "watch"]);

    三 HTTP缓存

    相信很多人对HTTP缓存有一定的了解,当然如果对HTTP的缓存机制和原理不甚了解,可以去看下这个网站,我觉得里面介绍的还是浅显易懂[http://www.cnblogs.com/chenqf/p/6386163.html]。

    其实这里的缓存,大多还是针对静态资源的缓存, 很多人可能明白了其原理,却不知道该如何实现

    1) 直接通过服务器配置,对访问静态资源进行缓存 ,如采用node的express框架的app.use(express.static(path.join(__dirname, 'public'),{maxAge:1000*60*60*30}));

    在资源数据返回的响应报文中,会返回相应的数据和缓存规则(缓存有效期max-age=108000),然后浏览器会根据返回的缓存规则执行相应的缓存机制。当然,如果你留意的话,会发现有些缓存提示是from memory cache,有些又是from disk cache,说实话,其中原理本人也不甚清楚,据本人实测及猜测,数据进行缓存时,会优先将数据缓存到磁盘上,然后浏览器再通过判断文件类型,将图片/css的文件缓存在内存中。当重新打开页面后,由于内存被清空了,浏览器会先从磁盘上读取,再缓存在内存上,故再次刷新后,图片/css的文件直接从内存中读取,而其它文件的直接从磁盘上读取。

    至于状态码200和304,出现304的原因的浏览器先访问服务器,服务器通过标识判断该文件没有修改,直接返回个304,然后浏览器通过状态码直接读取缓存(也就是对比缓存),200则是在数据未失效时,采用强制缓存,浏览器直接使用缓存中的资源。

    2) H5的应用程序缓存

    四 重绘和重排

    在理解重绘和重排之前,我们先回忆下网页的生成过程:输入网址 -> 加载html/css -> 将html转化成DOM树 -> 将css转化成CSSOM -> 结合两者生成一棵渲染树 -> 生成布局及将布局绘制在屏幕上,也就是人们常说的渲染。在这过程中,主要的耗时在于渲染这一步,主要存在以下几点原因:

    1. 浏览器在代码中发现一个标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码,当图片返回后,因影响到后面的排布,浏览器需要重新渲染;

    2. 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码;

    3. 浏览器发现了一个包含一行Javascript代码的标签,会立即运行该脚本并阻塞文档解析直到脚本执行完。(web的模式是同步的,开发者希望解析到一个script标签时立即解析执行脚本,并阻塞文档的解析直到脚本执行完。如果脚本是外引的,则网络必须先请求到这个资源——这个过程也是同步的,会阻塞文档的解析直到资源被请求到。因此在HTML5中,指明了一个新属性defer,以使其不阻塞文档解析,并在文档解析玩成后再执行,也增加了标记脚本为异步的选项,以使脚本的解析执行使用另一个线程。)

    4. 等到执行javascript脚本后,因为必要的一些dom操作,导致DOM树发生变化,如某些节点添加删除隐藏等,会导致浏览器重新渲染这部分代码。

    5. 过多的使用table布局。table及其内部元可能需要多次计算才能确定好其在渲染树中节点的属性,通常要花3倍于同等元素的时间。

    说了那么多,还是回到主题上,什么是重绘和重排?

    重绘就是一个元素外观发生,如改变visibility、outline、背景色等属性变化,导致浏览器重新绘制受影响的部分到屏幕上的一种行为。而重排就是由于DOM树结构/DOM节点元素属性发生变化导致浏览器因渲染树部分失效而重新构造渲染树的一种行为。重绘不一定需要重新布局,也就不一定会引起重排,但重排一定会伴随重绘。

    以下几点会导致浏览器发生重排:

    1、添加或者删除可见的DOM元素

    2、元素位置改变

    3、元素尺寸改变

    4、元素内容改变(例如:一个文本被另一个不同尺寸的图片替代)

    5、页面渲染初始化(这个无法避免)

    6、浏览器窗口尺寸改变

    如今浏览器大部分已经针对重排做了优化,通过队列优化修改并批量执行优化重排过程,一次性完成,但某些DOM操作会导致浏览器强制刷新队伍并要求计划任务立即执行,如获取元素的布局信息操作。

    故,在开发中应当尽量减少重排次数和缩小重排的影响范围。

    1. 将多次改变样式属性的操作合并成一次操作,或者先集合操作获取属性,再集中操作修改属性

    2. 将需要多次重排的元素,position属性设为absolute或fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位。

    3. 在内存中多次操作节点,完成后再添加到文档中去。如先生成HTML字符串,再整体赋值。

    4. 由于display属性为none的元素不在渲染树中,对隐藏的元素操作不会引发其他元素的重排。如果要对一个元素进行复杂的操作时,可以先隐藏它,操作完成后再显示。

    5. 在需要经常获取那些引起浏览器重排的属性值时,要缓存到变量。

    6. fragment元素的应用。

    相关文章

      网友评论

          本文标题:网站性能优化篇

          本文链接:https://www.haomeiwen.com/subject/jvsqjxtx.html