基于VUE的SPA单页应用开发-加载性能篇

1、基于异步数据的vue页面刷新

先看看基于异步数据的vue页面刷新后,都发生了啥~

如图所示:

图1 基于异步数据的vue页面刷新 网络请求图

步骤如下:

step1:请求页面;

step2:请求页面内的css、js资源;

step3:vue页面初始化;

step4:页面渲染,框架呈现[无数据内容];

step5:请求页面实际数据;

step6:数据ready,填充视图,图片资源加载;

step7:完整页面呈现。

步骤分析:

step1:请求html文件;

step2:请求资源;

优化点:

a、多次访问的资源缓存:可从MD5、组件打包方式等角度再细分;

b、app框架资源预加载:如果是hybird开发的app,可通过app框架预加载的方式,将单页应用的资源提前缓存。

单页的css、js资源,与传统页面的资源相比,规模要大很多。其集合了几乎单页应用的所有css、js文件,随着应用的规模大小成正比增长。合理的缓存处理,将大大提升页面加载速度。a、b两点可实现性能加速的原因是,本地加载过的资源,会缓存在本地;页面请求资源时,浏览器会先查找缓存,如果有缓存,则本地取,节省了网络请求。[可了解浏览器的强缓、弱缓]

step3:页面初始化;

优化点:

利用v-if指令按需加载组件~

由于vue在初始化过程中,会深度查找子组件,生成依赖,构建虚拟DOM,所以其初始化时间相对较长;不过在查找过程中,遇到v-if为false的组件,将停止深度查找,从而节省初始化时间。由此可通过控制v-if的布尔值,实现性能优化和组件的按需加载。例如在初始化过程中,仅首屏必须的组件v-if=true,其他组件[如非首屏组件、弹窗组件等],可在下一事件循环中[通过setTimeout(fn, 0)等异步操作可实现],或者首屏资源加载完成后,开启。

step4:默认数据页面渲染;(默认数据由vuex提供)

优化点:无数据的页面框架的渲染展现[通常所说的灰框],让用户提前感知页面,从而提升用户体验;(包括读取vuex数据,进行渲染)

step5:异步请求数据,与step4同时进行,通过ajax实现;

step6:资源加载;

优化点:进行图片[视频]分批加载优化,从而增加同一带宽下单图的加载速度,加速首屏展现。

建议图片加载流程:

step6-1:首屏展现必须图片加载及首屏默认图片;[如:banner图第一张];

step6-2:首屏其余图片加载及其他默认图片;[如:剩余的banner图];

step6-3:非首屏 or 弹窗。[接下来的加载顺序,可根据需求调整。但要遵循一条原则,不影响首屏的用户交互。]

2、基于异步数据的vue页面的路由跳转

再来看看通过单页路由跳转到新页,又发生了什么?

图2 基于异步数据的vue页面路由跳转 网络请求图

页面加载步骤:

step1:捕获到路由变化;

step2:初始化该页面,并默认数据渲染;(包括读取vuex数据,进行渲染)[step3、step4]

step3:异步请求最新的初始化数据;[同step5]

step4:资源分批预加载。[同step6]

总结:

优势:页内跳转性能非常赞。对比图1和图2,在路由内跳转时减少了图1中step1、step2的页面请求和.css、.js的请求时间[节省1s+],页面展现嗖嗖的。再好好结合vuex的数据流,可以给用户非常棒的体验。

劣势:再观察图1的网络请求图,可以发现以下几点:

a、css、js资源相对传统页面,量更大,加载时间加长;

b、vue的首屏展现,依赖异步数据的请求,相对传统同步页面,增加了单独的数据请求时间消耗;

c、页面渲染,在js执行完毕之后,才开始进行;而最终的首屏展现,则需要等待异步数据请求到达之后。

由于a、b的存在,c的首屏展现时间相对传统页面更慢。

VUE的异步单页应用优势与劣势非常明显,缺点是初始化时间长,依赖js资源的加载;优势是运行速度快,路由内跳转几乎没太多的时间消耗。如果是一定规模大小的单页应用,它将是不错的选择。特别是使用hybird开发,通过app框架将资源预加载之后,需依赖js资源的劣势也必将不存在,那将给到用户传统页面无法给到的体验。

Q:那有什么办法来解决这些劣势吗?

A:在接下来的3中,将提出一种解决方案。

3、提速方案

对于a点,资源量大,可以从打包方式、缓存、CDN分发等角度进行处理;

对于b点,有两种方式解决:

1、同步+异步数据请求:刷新页面时,使用同步MVC框架的方式,通过后台路由带入初始化数据;页内路由跳转时,仍然采用异步的方式进行。

2、异步数据请求提前:刷新页面时,将数据请求提前至js资源加载前,由于网络请求可并发多个,将节省单独的数据请求时间。

tips:如果不是mvvm的异步单页,推荐使用同步+异步的方式,页面的展现可以提前至js资源加载之前。[由于mvvm框架下的页面视图通过数据进行驱动,该驱动的基本需要依赖js脚本实现,所以必须等待js加载完毕,才能正确展现页面。因此,在mvvm框架下,同步+异步的方式仅能节省数据请求时间,但其他单页应用可以节省数据请求时间+js资源加载时间]

ps:js的加载顺序:不影响页面初始化呈现的js底部后置:如日志、分享、im的相关js。

4、初始化性能优化[可用于加速首屏呈现]

如下示例:

其页面结构与组件结构关系图如下:

vue初始化的组件编译原则是,按照深度查找,遇到v-if为false的节点或者叶子节点,停止查找。从示例的组件结构图,我们可以看出,

初始化中组件查找过程为:

step1:首先查找根节点的子组件nav组件,其为叶子节点,编译,返回;

step2:查找app的第二个子组件(节点)content,其非叶子节点,且无v-if标记,继续深度查找;查找其子节点c-a组件,为叶子节点,编译,返回content;查找另一个子节点c-b组件,叶子节点,编译,返回;

step3:节点content查找完毕;返回app,查找sidebar节点,sidebar非叶子节点,且无v-if,继续深度查找;同step2,最终返回app节点。

step4:所有组件编译完毕,初始化完毕,渲染。

如上示例,将深度遍历所有子组件,再完成渲染。如果将首屏不需要展现的组件设置成v-if,将降低深度查找的复杂度,从而加速组件初始化,加速页面的呈现。

加速代码如下:

            newVue({    data: {        showContent:false,        showSidebar:false},    created () {//显示content        setTimeout(()=>{this.showContent =true;        },0);//显示sidebar        setTimeout(()=>{this.showSidebar =true;        },0);    }});

以上代码将组件content与sidebar的v-if设置成false,组件的编译查找过程如下:

step1:不变;

step2:查找content组件,其为v-if=false,停止,并返回根节点;

step3:查找sidebar组件,其为v-if=false,停止,并返回根节点;

step4:所有组件编译完毕,初始化完毕,渲染。

是不是快了很多~~由此,首先被渲染,出现的是nav组件结构;另外两个组件通过showContent,showSidebar控制。

为何这里使用setTimeout(fn, 0)控制两个组件的状态变化呢?

因为setTimeout是时间异步处理模块,通过其设置,相应的处理方法将在下一事件循环中才被执行,而VUE的渲染时机为本次主线程执行完毕。如此,使得另外两个组件的编译推迟到首次渲染之后,从而实现组件加速。

tips:这里需要注意,不是将组件设置v-if=false就可以了,要看看v-if=true的开启时机,如果是同一事件循环中被开启,便没有意义了。因为vue的数据驱动渲染时机,是同一事件循环中的代码全部执行完毕之后,拿到数据的最终状态才进行。同时,setTimeout(fn, 0)也不可乱用。

附加:图片分批预加载的js脚本

参数说明:

auto: 是否自执行

imgs: 需预加载的图片列表,为二维表

ignore:在自执行过程中,需要跳过的图片批次脚标

firstSetReady: 第一组图片完成加载以后,置为true,便于外部掌握状态[一般首屏资源为第一组图片]

finished: 所有图片资源加载完毕

说明:

非自执行的需求,可直接调用loadOneSetImages方法,返回值为promise

letco =require('co')classPreload{// 定义构造函数的数据结构,创建实例对象时,自动初始化constructor(auto, imgs = [], ignore = []) {this.imgs = imgs;this.ignore = ignore;this.auto = auto;this.firstSetReady =false;this.finished =false;this.init();    }// 初始化函数init() {letme =this// 如果自动执行,则调用co模块,自动加载资源if(this.auto) {// generator的自执行函数,资源加载完毕时,参数finished置为trueco(this.autoExeImageStream.call(this)).then(function(){console.log('资源加载完毕~')                me.finished =true}).catch(function(){console.log('资源加载出错~')                me.finished =true})        }    }// 同步加载分批图片资源,使用generator函数,完成当前批次加载,再启动下一批次的加载* autoExeImageStream() {letrstList = []for(leti =0; i

图片分批预加载脚本通过ES6 promise结合generator函数实现,使得图片按照我们想要的方式顺序加载,且单批次速度更快。但不能滥用,需要留意图片资源的加载规模与用户交互操作之间的关系。由于,ES6 的 promise在事件循环中的消息处理级别高于DOM事件[or 网络请求等其他异步模块],当有 promise 消息要处理时,其他事件消息将等待,直到promise处理完毕。因此在使用其进行预加载时,一定要结合业务情况及预加载的需求进行设置。如有需要可以创建多个preload实例,通过一定的条件,触发图片预加载,将其进行分散,从而达到性能加速的同时,用户交互体验也不受影响。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,392评论 25 707
  • 30余年的第一次出去旅行,第一次坐飞机,飞机飞起的那一刻我在想,儿子,你没坐过飞机,下次妈妈一定带你...
    傻傻的二丫头阅读 198评论 2 1