用户
 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,登录网站

小程序社区 首页 教程 查看内容

小程序启动速度优化实践

Rolan 2021-9-14 11:07

良好的启动速度无异于会带来良好的用户体验。本篇文章主要介绍每日优鲜主商城小程序的启动速度优化方法。

前言:前端应用的启动速度一向是移动终端的优化重点,因为这是面向用户进入的大门。良好的启动速度无异于会带来良好的用户体验。

本篇文章主要介绍每日优鲜主商城小程序的启动速度优化方法。

启动时间消耗概览

小程序的启动时间主要分为以下几个阶段:

微信客户端比对版本差异,下载并加载代码。
小程序本身的初始设置,业务逻辑请求处理。
页面的渲染。
所以,小程序从点击启动到渲染完成主要会经历以上几个过程,接下来我们针对以上部分进行优化说明。

代码下载加载阶段
众所周知,小程序本身使用的是JS,HTML,CSS等语言进行开发。所以在代码发布时,微信会对这些文本文件进行必要的体积压缩。除此之外还有应用所需的图片资源文件。

所以发布后的小程序主要包括:

压缩后的JS,HTML,CSS等文本文件。
应用中所需的图片资源文件。
这些文件的总体积便会影响到小程序第一阶段的加载速度。而在这些文件中,图片资源文件占了总体积将近80%的比例。

所以,针对这一阶段的主要优化方式为:

将不必要的图片资源存储于服务器,通过url加载。 不必要的图片资源包括但不限于:营销活动的背景图、活动的规则说明图、活动Banner、GIF图等。在优化时,按照文件大小从大到小排序,分情况处理。

将必要的Icon图做压缩,如果不需要Aphla通道的图可转换为JPEG格式。
推荐在线图片压缩处理网站:https://tinypng.com/

对于按钮背景图等可使用CSS达到同样效果的使用CSS绘制。

避免冗余代码,及时移除废弃代码。

代码初始化,业务逻辑请求处理
这一部分主要与业务本身联系紧密,需要根据业务需要来进行优化处理。以下主要针对主商城的业务模式进行优化说明:

小程序优化之前的启动过程如下:

登录 -> 获取上次下单地址 -> 请求货架信息 -> 通过购物车信息 -> 渲染
第二次启动过程如下(与首次相同):

登录 -> 获取上次下单地址 -> 请求货架信息 -> 通过购物车信息 -> 渲染
小程序优化之后的首次启动过程如下:

登录 -> 获取上次下单地址 -> 请求货架信息 -> 分页渲染 -> 同步购物车信息
第二次启动过程如下(没有登录过程):

获取用户上次下单地址 -> 请求货架信息 -> 分页渲染 -> 同步购物车信息
可以看到,这里主要针对登录做了优化,并将页面渲染前置。

在优化过程中,发现小程序每次都会重新登录,显然不需要这么做。如果将登录状态存储在本地,可以减少登录一系列过程的开销。但是为了保证登录状态的过期问题,所以专门对网络框架层做了处理:如果后端返回statusCode为401或者403,或者statusCode为200但是内部的code为102,则会重新走登录过程。登录完毕之后会再次请求原有的接口,好处在于业务层并不需要关心也不会感知到token过期的问题。

渲染
在优化之前,小程序会显示一个Loading图,直到购物车信息同步完毕。我们为了尽快的将信息展示给用户,将这个Loading图前置到了货架信息开始渲染时,也就是说,在渲染货架信息的时候,便不再显示Loading。这个过程很重要,对启动速度影响很大。

除此之外,在初次渲染时只渲染少量的数据,但足满一屏。通过测试发现,渲染全部数据与渲染一屏的数据时间差异较大,我们在用户需要查看更多数据的时候,再对剩下的数据同样进行分页渲染:货架数据一次10条。

页面渲染的同时,我们也在同步购物车信息,做到了并行进行。在同步完成之后,再将购物车的信息更新到货架上。

总结
经过以上大幅优化手段,小程序启动速度明显加快。在开发者工具上的运行结果为:之前首次是4秒,优化之后首次是2秒。第二次进入之前还是4秒,优化之后为1.5秒。可以算是”秒开“了。

这里我们并没有涉及网络优化方面,但这并不意味着网络部分不需要优化。如果在实际开发中,网络部分不再合理的范围内,则需要考虑服务器相关的优化:代码优化、DNS优化、服务器地理位置优化、网络环境优化、网络包压缩以及适时不采用HTTPS等加密传输等方向。另外由于小程序是运行在微信内置的相关引擎上,所以在我们不可控的范围内也有一定的开销,这一部分需要及时关注微信方面的更新。

工具
优化应用需要一个得力的工具,这里为大家共享一个执行时间统计工具,这款工具可以统计两个点之间所花费的时间,使用方便简单。以下是JS语言,其它语言可参考实现方式:

let index = 0;

function logTime(arg) {
  index++;

  const app = getApp();
  let current_date = new Date();

  let offsetTime = 0;
  if (app && app.globalData.lastTimeLogFunctionCallTime !== 0) {
    if (app.globalData.startTotalTime == 0) {
      app.globalData.startTotalTime = current_date.getTime();
    }
    offsetTime = current_date.getTime() - app.globalData.lastTimeLogFunctionCallTime;
  }

  let desc = current_date.getMinutes() + "分" + current_date.getSeconds() + '秒' + current_date.getMilliseconds() + "毫秒";

  if (app && app.globalData.startTotalTime != 0) {
    let totalStartTime = new Date(current_date.getTime() - app.globalData.startTotalTime);
    desc += ", 启动总耗时: " + totalStartTime.getMinutes() + "分" + totalStartTime.getSeconds() + "秒" + totalStartTime.getMilliseconds() + "毫秒";
  }
  if (offsetTime != 0) {
    let time = new Date(offsetTime);
    desc += ", 与上一次调用的差值为: " + time.getSeconds() + "秒" + time.getMilliseconds() + "毫秒";
    if (DEBUG_STACK_MODE) {
      let currentCallStack = (new Error).stack;
      desc += ", 当前的调用栈为: " + currentCallStack;
    }
  }

  logi('TIME_TAG ==> ' + index + (arg ? " " + arg : "") + ' 当前方法的调用时间为: ' + desc);

  if (app) {
    app.globalData.lastTimeLogFunctionCallTime = current_date.getTime();
  }
}

function logi(infoMsg) {
  if (DEBUG_MODE) {
    console.info(infoMsg);
  }
}
文章本身就到此结束了,但结尾有些潦草,对感兴趣的同学借鉴意义也不大。因为大幅节省时间的点还是在于业务本身。不过上面的工具帮助我定位了哪一段代码之间具体的执行耗时时间,还是比较有用的。
————————————————
版权声明:本文作者「Sahadev_」,版权归作者所有,商业转载请联系原作者
原文链接:https://blog.csdn.net/sahadev_/article/details/120078928
鲜花
鲜花
鸡蛋
鸡蛋
分享至 : QQ空间
收藏
原作者: Sahadev 来自: csdn