title: 首屏优化系列(一) date: 2018-6-23 13:53:30 tags:
- Promise
- 图片懒加载
- 路由懒加载 categories: 前端
八一八本次项目中使用的优化手段,以及自己从中获得的知识。 由于本次项目较为复杂,模块较多,(当然不比大型电商网站),首页的请求就有8个,并且是精简之后的,稍有不慎,白屏现象就会很严重。体验极差。 ## 首页模块划分 1. 分类 2. 轮播图 3. 推荐 4. 收藏数 5. 购买数 6. 案例展示 7. 主内容展示 8. 合作机构展示需求描述:优化首屏加载速度,减少白屏时间。
其中位于首屏的是1、2、3、4、5,对于6在大屏幕上也会展示。
优化手段
Skeleton Screen (骨架屏)
简单来说,骨架屏就是在页面内容未加载完成的时候,先使用一些图形进行占位,待内容加载完成之后再把它替换掉。体验的效果就是,在页面完全渲染完成之前,用户会看到一个样式简单,描绘了当前页面的大致框架,能够感知到页面正在逐步加载,最终骨架屏中各个占位部分被完全替换。显示效果如下:
路由懒加载
把不同路由对应的组件分割为不同的代码块,当路由被访问的时候,再加载对应的组件,对中大型项目来说,会显得很高效,对开发者而言,也方便维护。不过这里要对生产环境和开发环境做区分,因为如果项目很大的话,每次更改代码触发的热更新时间都会很长,所以只在生产环境中使用路由懒加载。
// 生产环境 _import_production.js
module.exports = file => () => import('@/pages/' + file + '.vue');
// 开发环境 _import_development.js
module.exports = file => require('@/pages/' + file + '.vue').default; // vue-loader at least v13.0.0+
// router.js中引用
const _import = require('./_import_' + process.env.NODE_ENV);
{
path: 'course',
component: _import('course/index'),
name: 'course'
}
复制代码
图片懒加载(vue-lazyload)
// 安装
npm install vue-lazyload --save-dev
// 使用 main.js
import Vue from 'vue'
import App from './App.vue'
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
Vue.use(VueLazyload, {
preLoad: 1.8,
error: require('@/assets/lazy/error.png'),
loading: require('@/assets/lazy/loading.png'),
attempt: 1,
listenEvents: ['scroll']
});
new Vue({
el: 'body',
components: {
App
}
});
// 在使用图片的地方加上v-lazy即可
<img v-lazy="img.src" >
复制代码
更多使用方式可参考vue-lazyload 这里呈现的效果就是,请求完成数据,再去请求阿里云存放的图片,这个阶段中,图片资源加载过程中,显示loading的状态,加载完毕,显示图片,如果图片加载失败,显示失败的图片。
Promise
回到我们最初的问题,课程首页的请求数为8,请求都为异步请求,而我们的浏览器对同一域下的请求数量是有限制的,超过限制数目的请求会被阻塞,以谷歌浏览器的6个并发请求量为例,课程首页的数据请求和图片请求加起来成百上千个,上面,我们对图片请求已经做了处理,使用懒加载的方式,另外,放在和数据请求不同的域下,我们需要考虑的就是数据请求,目前为8个,我做过这样的测试,如果同时发出的话,每个请求的时间大概是50ms,当每次单独发送一个请求的时候,每个请求的请求时间大约十几毫秒,所以我当时的解决方案就是使用setTimeOut,进行延迟请求,这样做的话,我需要单独测试每个请求的时间,然后为他们写延迟时间,这样效率是很低的。此外,跟promise比,setTimeOut的执行优先级会降低,后来采用了promise的方式,如下:
return new Promise((resolve,reject) => {
})
复制代码
采用这种方式的另一个原因是,如果所有异步请求同时触发的话,浏览器会为他们分配执行的优先级,而采用这种方式,请求的顺序会按照我们调用的顺序执行。而浏览器分配的话,可能页面底部的请求会先执行。在请求较少的情况下,这种差异是体现的不明显。
提到promise,我觉得最大的好处就是如它设计的初衷那样,解决了层层回调的问题(难以维护,且不优雅)--链式调用,还有Promise.all()的用法,对于组合数据很方便。
浏览器缓存(localStorage)
对于不频繁修改的数据做了缓存,并且根据变换频率,缓存时间不同。
if (cacheTime < 0) cacheTime = 3600000;
var result = { data: response.data, expiration: new Date().getTime() + cacheTime };
localStorage.setItem(cacheName, JSON.stringify(result));
复制代码
详细的缓存方法,已上传至github:前往查看
PageSpeed Tools
这个工具可以在谷歌的插件商店中下载,很好用,能列出所有需要优化的点。 本地所提示的图片问题,如使用浏览器缓存,需要在服务器设置etag和expire time 。 测试加载的时间可以用
console.time('加载时间');
console.timeEnd('加载时间');
复制代码
参考文章:
- 网站性能优化实战——从12.67s到1.06s的故事
- Event Loop浅谈
- JavaScript 工作原理之十一-渲染引擎及性能优化小技巧
- 基于Vue的SPA如何优化页面加载速度
- 为vue项目添加骨架屏
- 浏览器允许的并发请求资源数是有限制的-分析
- 变态的静态资源缓存与更新 目前还只是个渣渣,以上只是我的个人理解,如有不足,还请指出,不胜感激。