东亚银行、岚图汽车带你解锁 AIGC 时代的数字化人才培养各赛道新模式! 了解详情
写点什么

启动耗时降低 30%!腾讯在线教育小程序开发实践与优化

  • 2019-07-03
  • 本文字数:6343 字

    阅读完需:约 21 分钟

启动耗时降低30%!腾讯在线教育小程序开发实践与优化

在日前的 GMTC 全球大前端技术大会上,腾讯前端高级工程师陈超发表了《腾讯在线教育小程序开发实践之路》的演讲,介绍了腾讯在线教育在微信小程序、QQ 小程序上面的平台类、工具类、内容类小程序的开发实践之路以及优化方案。本文整理内容如下。

腾讯在线教育小程序矩阵

首先介绍下腾讯在线教育下的 3 个主要业务:



  • 面向成人职业化,兴趣化学习的腾讯课堂

  • 面向小学,初高中 k12 领域的企鹅辅导

  • 面向少儿英语学习的 ABCmouse


每个业务下都有 PC Web,客户端,H5,APP 这几端,来满足学生的多端上课需求。但由于教育的前身是基于 QQ 群视频孵化出来的,后续也是围绕 QQ 生态去搭建产品形态,所以在流量上面,QQ 相关的流量占比较多。



我们希望能够通过小程序生态,来为教育业务带来微信端流量的增长,并且优化学生的微信端上课体验,所以我们打造了在线教育的小程序矩阵。




我们通过工具,内容型的小程序,来获取流量。比如腾讯课堂打开小程序,腾讯微课堂,企鹅速算,口语拼读等工具型小程序,并最终转化到平台小程序上。

小程序基础架构设计及工程化探索

上面提到的那么多小程序,我们是如何进行框架选型


以及团队在多人协作的开发中,是如何制定统一的开发规范,小程序工程化的探索呢?下面将一一介绍。



框架选型时,我们对小程序几大主流开发框架,taro, wepy, mpvue 跟原生开发框架进行了对比。可以看出原生框架在 CSS 预处理,多端复用,管理,自动构建这几块能力对比其他框架是欠缺到。但考虑到以下几点,我们比较倾向于使用原生框架进行开发:


  • 小程序的特性更新迭代速度较快,我们希望能最快使用上最新特性,其他第三方框架可能会有迭代滞后到问题。

  • 我们的多端复用需求较弱。

  • 对性能调优,问题排查要求较高,希望直接操控原生 API。


那么以上这些开发上的缺陷,使用原生框架是否可以解决,如何解决呢?

1. CSS 预处理

首先来看 CSS 预处理,我们是期望能够在小程序中使用到 CSS 预处理,包括嵌套语法,mixin,变量等以及 styleLint 等工具。


经过调研后,我们可以直接使用 postcss 来写样式文件并编译处理成 wxss。




并且通过引入插件,可以解决小程序样式开发中的痛点。比如 postcss-url 解决 background-image 不支持本地图片问题,将其变成 base64 格式;通过 postcss-font-base64 插件将字体变成 base64 格式。

2. 数据管理

数据管理方面可以使用 westore 来接入。

3. 构建


小程序的构建需要完成什么事情呢?小程序开发者工具已经提供了部分能力: ES7/ES6 转 ES5,NPM 包管理,代码分包,组件化,打包合并。我们借助 gulp 来实现图片压缩以及前面提到的 Post CSS 编译 。


为什么使用 gulp 而不用更流行的 webpack 呢,


这里补齐的能力主要涉及文件处理比较多,使用 gulp 开发效率较高,小程序一些官方脚手架也是使用 gulp。



最后,我们选择了小程序原生框架作为我们的开发框架。并且补齐了跟其他开发框架对比欠缺的基础能力。当然,这里并非说其他框架不好,具体选择还是需要看具体的业务场景。

4. 目录规范


确定好开发框架后,统一的目录规范也是团队协同开发必须约束的。


在引入 npm 包管理后,我们在小程序的基础目录中,通过新起了一个 miniprogram 目录来作为小程序代码的根目录。这是由于小程序会对 node_modules 里面的包打包编译到 miniprogram_npm 目录,为了避免小程序的 node_modules 跟其他工程化相关的 node_modules 混在一起,才新起了一个文件夹来存放小程序工程代码。可以通过修改 project.config.js 可以配置小程序代码的根目录路径。

5. 编码规范


约束好目录,那么在团队协同开发,如何维护规范化,风格统一的代码,我们希望可以团队成员开发时可以统一代码规范, 提交规范, 风格保持一致。因此,跟我们其他 web 项目一样,我们可以使用 eslint,stylelint,commitment,prettier 等插件来对我们的代码进行约束,规范。通过 git hook 来在做提交时的校验检测,不通过则不允许提交。


通过 Commitizen 以及 standard-version 来自动化生成统一的版本号以及 ChangeLog。会自动将你在本次版本迭代中,提交的规范化 log(遵循 Angular 团队的commit规范自动生成 ChangeLog, 注明是特性发布,bugfix 还是 breakingChange,以及对应的 log 信息。后续我们在需要回滚或者回溯某一版本的改动时,就可以一目了然。


我们基于上面的能力以及约束规范,做成统一的脚手架,方便团队在统一的环境下快速开发,并且开源了:https://github.com/imweb/generator-imweb-wxapp

小程序开发实践

介绍完我们的框架选型,工程化探索,接下去分享下在线教育小程序的开发实践经历。

小程序音视频


第一部分是小程序音视频能力相关的实践。腾讯课堂是一个在线学习的平台,那么最核心的就是音视频直播,录播能力。那么在小程序上面,我们如何搭建课堂音视频能力呢?

1. 直播场景


我们先来看未接入小程序前,腾讯课堂的直播架构。我们通过老师上行到云上,再实时下行到端上, App 学生以及通过 WebRTC 下行到 PC web 学生。对于延迟要求不高的场景,我们可以将直播流旁路转码到 CDN,再供用户拉流观看,以节省成本。



这是各端使用的直播协议以及延迟对比,小程序应该采用那种协议,如何接入呢?



揭秘之前,我们先来了解下小程序音视频能力的发展历史。最初,小程序音视频只有原生的 video 标签。意味着只能支持 HLS 高延时直播场景。



2017 年 4 月份,腾讯云与小程序达成合作,在小程序上嵌入腾讯云音视频 SDK,并封装成了 live-pusher,live-player 标签,使小程序能够支持更低延迟的直播协议,如:rtmp, http-flv 等。


因此,我们可以使用 live-player 来播放 rtmp,http-flv 协议的流媒体来播放,降低小程序直播场景上的延迟。



不过目前 live-player 还存在一些不足:


  • 比如全屏按钮不支持,需要自己定义。

  • 由于 live-player 是原生组件,因此需要通过 cover-view 以及一些 hack 方式来实现自定义控制条的全屏按钮跟视频窗口显示层级的 bug。

  • IOS 全屏时,bindevent 无效。


不过小程序后面采用同层渲染的方案,解决了原生组件需要使用 cover-view 来解决显示层级问题,使用最新版本的基础库即可。



使用 live-player 大概 1-2s 的延迟,那么小程序上还有没更低延迟的直播方案呢?


加入你是在腾讯云上面开通了 WebRTC 后,可以使用 wbertc-room 去实现小程序上更低延迟的直播。其原理是基于 live-player 的 RTMP,但走的高速专线,不经过 CDN,降低了延迟。



(小程序接入课堂音视频的整体架构图)

2. 录播场景

介绍完直播接入方案,接着讲下录播。由于版权保护,腾讯课堂录播播放采用了加密 HLS。



由于录播对延迟没要求,小程序上面可以直接使用 video 标签来播放加密 hls 流。



在 Web 上,播放加密 HLS 的流程如下:


  1. 获取到加密 HLS 的 m3u8 地址,传给 video;

  2. 浏览器 video 底层解析 m3u8,发现其带有加密协议标识-EXT-X-KEY,其值是一个获取解密 key 的接口地址;

  3. 浏览器会自动发起该请求,发起请求,去获取解密 key;

  4. 浏览器自动发起请求时,会把用户登陆态通过 cookie 方式带上,业务后台对 cookie 鉴权后返回解密 key,之后浏览器拿到解密 key 后就可以解密播放了。


但在小程序中,由于小程序是没有 cookie 的,那么怎么去针对小程序发起的获取解密 key 请求鉴权呢?




我们通过在获取 m3u8 文件时,在 meu8 地址加入加密后的鉴权参数,并加上前缀"voddrm.token.",这样 server 返回 m3u8 文件时,会在 EXT-X-KEY 的请求地址上,将鉴权参数拼接进去。后面发起请求时,业务后台获取到鉴权参数,按照协商好到方式解密,即可获取到用户登陆票据进行判断是否合法用户。之后就按照之前的流程,鉴权通过即返回解密 key。

小程序自动化发布

补齐了音视频能力后,我们项目也正常上线。由于平台功能不断增加,小程序也在按照以下流程进行迭代发布。



但是上面流程是存在一些隐藏问题的,特别对于新人,容易因疏忽导致出错,我们也因此导致了一个现网 bug。不知道大家能发现不?



揭晓下答案,主要有 2 个问题:


  1. 多人开发过程,npm 包可能存在不同版本,比如登录能力的 npm 包,有可能会忘记更新最新包。

  2. 构建 npm 按钮在开发者工具上面入口比较隐蔽,容易导致更新了 npm 包但是忘记点击构建 npm,覆盖了线上的特性.


上面操作对于熟悉小程序开发的人来说不容易出错,但对于新人,由于不熟悉,容易疏忽。即使犯错但概率很小,但是也必须解决。


那么我们能否通过自动化工具来帮我们校验检测这些隐患呢?



我们希望在上传发布前,可以进行以下流程的自动检测:


  1. 代码合并主干检测。

  2. node_modules 版本检测,必须是大于或者等于当前 package.json 的版本。

  3. 自动执行构建 npm 操作。

  4. 自动执行上传操作,包括填写版号以及备注信息。


其中 1 跟 2 可以通过 githook 以及 npm 命令来判断,3 跟 4 涉及到小程序相关到能力调用,是否有暴露相关到接口可以调用呢?



这里小程序开发者工具提供了命令行以及 http 调用方式:https://developers.weixin.qq.com/miniprogram/dev/devtools/cli.html


,可以让你操作项目打开/关闭,代码上传,预览,构建 npm, 自动化测试等功能。因此,我们利用这个能力,采用 cli 调用等方式,实现了构建 npm 以及自动发布等能力。



具体流程如下:


  1. 进行是否更新最新主干代码检测;

  2. 判断是否安装了小程序开发者工具且正常设置到环境变量;

  3. 进行本地 node_modules 版本检测;

  4. 调用构建 npm 命令;

  5. 自动获取 package.json 的版本号作为上传版本,获取 git 提交 log 作为备注;

  6. 调用上传命令进行上传



自动化发布流程示例

小程序第三方平台

有了以上工具后,我们就可以愉快地进行开发迭代发布了。但随着我们课堂平台小程序的推广,课堂平台的各家机构都想拥有其自己的机构小程序,并且其页面是课堂平台小程序的一个子集。



通过分析后,我们决定通过构建的方式,从平台小程序中拆离出机构小程序代码。通过 2 份模版配置信息, 通过构建,可以动态生成平台小程序以及机构小程序的 app.json。这样进行上传的时候,就只会上传对应的页面。


代码复用的问题解决了,但随着而来还有另外一个问题。需要生成的机构有 80 多家,有些机构不一定有开发人员,如果帮助机构快速上传发布他们自己的机构小程序呢?



这里引入微信第三方平台的概念,我们可以往微信开发平台申请成为第三方平台。机构申请完独立的小程序账号后,将其授权给我们腾讯课堂第三方平台。这样我们就可以获取到该机构到代码管理,版本发布到权限。通过上传我们之前构建好到机构小程序模版,再调用发布接口,就可以快速实现帮助机构发布其独立个体到机构小程序了。

性能优化实践


我们的小程序上线后,通过在小程序管理后台看到的启动总耗时,发现几个问题:


  1. 小程序管理后台只展示了启动总耗时,下载耗时,渲染耗时这 3 个数据纬度,但是启动总耗时!= 下载耗时 + 渲染耗时;

  2. 启动耗时居然达到了 3.8s,这是一个合格都数据吗?除了下载耗时跟渲染耗时,其他耗时消耗在哪个环节呢?


要想知道耗时消耗在哪里,首先要先了解小程序启动过程中究竟发生了什么。



**1. 小程序初始化 **


在这个步骤,微信会初始化小程序环境,比如逻辑层的 js 引擎,视图层的 WebView,并且注入公共基础库。


**2. 下载小程序代码包 **


这里会进行业务小程序代码包的下载。


**3. 加载业务代码包 **


对下载完成对代码包进行注入执行 - 小程序的代码会被加载到适当的线程中执行。此时,所有 app.js、页面所在的 JS 文件和所有其他被 require 的 JS 文件会被自动执行一次,小程序基础库会完成所有页面的注册。


**4. 初始化小程序首页 **


拉取数据,从逻辑层传递到视图层,生成 VD 树,进行渲染。


了解完小程序的启动过程后,我们经过分析定位,个阶段耗时如上图所示。



其中灰色部分是小程序底层的执行耗时,这块开发者是无法操控的。那在其他耗时中,下载代码包这块占比比较高。我们能怎么去减少这块耗时呢?




原先对课堂小程序的所有页面都是在一个包里面,那么这里我们采用分包方案。将主 tab 的 3 个页面以及 util, 常用组件这种公共模块放在主包。其他每个页面单独分成 300-500k 左右大小对子包,子包可以引用主包对公共模块。


经过分包处理后,下载代码包对耗时减少了 500ms 左右,整体启动耗时降到了 3.2s。整体来说,已经比小程序大盘平均启动耗时 4.5s 少了 1.3s。



不过随着而来的,也有其他问题的引入,比如从首页打开课程详情页这一场景。



这个时候点击详情页时,需要先下载完详情页分包,才能打开课程详情页,显然这样的体验是极差的。



我们可以通过分包预加载的方案,来解决这个问题。打开首页,加载完主包后,可以静默加载其他分包,通过配置 preloadRule 即可实现分包预加载。



下面是一组本地测试数据,可以看到使用分包以及分包预加载的方案,可以减少启动耗时以及提高用户体验。



除了普通分包方案,小程序还有独立分包的方案。不依赖主包加载,即可打开分包页面。常用于一些比较独立的页面,比如活动页等。



但使用独立分包也有一些限制:


  • 独立分包无法引用主包或其他分包的资源。

  • 全局 App 对象只能在主包定义,独立分包不能使用 App 对象。

  • 生命周期只能通过:wx.onAppShow, wx.onAppHide 来监听。


解决了代码包下载的耗时以及采用分包,以及分包与加载提高页面打开性能以及效率。我们接下来看渲染耗时这块。



这是一个典型但小程序双线程通信的模型。每次调用 setData 方法,都会将数据从逻辑层传递到 native 层,再到渲染层,形成 VD 树进行渲染。



以上是 setData 传输数据量以及传输时间的关系图,可以看到当数据量大于 64kb 时,传输时间呈指数级增长。


因此,在使用 setData 时,应该尽量遵循以下建议:


  • 不要频繁调用 setData, 尽量合并到一次 setData 调用。

  • 传输数据量跟通信性能有关,尽量少于 64k,避免一些不需要在页面展示的复杂数据结构或者长字符串。

  • 与界面无关的数据最好不要设置在 data 中。

  • 去掉不必要的事件绑定,减少通信的数据量以及次数。

  • 不要在节点 data 前缀放置过大数据(需要传输 target 的 currentTarget 和 dataset)。

公共基础组件库

为了提高开发效率,代码复用率,我们对常见的一些能力以及功能型组件进行了封装(后续计划开源)。



这里拿基础能力的 request 组件来看,我们基于 wx.request 来封装,利用 storage 来存储登陆后的 cookie 信息,并在后续发起请求的时候,将登陆票据设置到请求头中。


采用可插拔插件式封装方法,来做各种插件到扩展。例如有 loading 插件,一个可以在发起请求的时候,自动显示 loading,请求完成后,自动隐藏的插件。



以上就是小程序开发实践相关的分享。

QQ 小程序


QQ 小程序是一个基于手 Q 庞大流量,面向年轻化群体,跟随小程序行业标准的小程序平台。启动于 18 年 12 月份,并于 6 月底全量发布,目前覆盖微信小程序 API 达到了 95%以上。




从用户侧来看,基本跟微信小程序类似。在聊天下拉即可发现小程序入口,里面有小程序商城,可发现各类小程序以及小游戏。它的开发者工具的 UI 也类似微信开发者工具。


它跟微信小程序之间有以下的一些区别:


API 以及功能方面


  • 调用前缀:例如:qq.getSystemInfoSync (也兼容 wx 语法) ,覆盖率 95%。

  • webview: QQ 小程序暂不支持 webview 。

  • 唤起方式:支持 http 链接唤起小程序。

  • 组件:不支持 live-player, live-pusher 组件。

  • 分享:QQ 小程序支持分享到 QQ 空间。


开发者工具方面


  • 底层框架:都是基于 nw.js。

  • 编译能力:

  • 不支持增强型编译。

  • 不支持多核心编译。

  • 其他

  • 不支持体验评分。

  • 不支持自动化测试。


总的来说,QQ 小程序的 API 基本对齐微信小程序,它的迭代速度较快,能力逐渐补齐中。并且拥有 QQ 生态流量红利,最重要的是从微信小程序迁移到 QQ 小程序工作量较小,代码 95%以上基本可以复用。

总结

小程序生态发展之迅速,支付宝,百度等各大厂商都在各自研发自己的小程序。从开发者的角度来说,希望能够统一一套 API 规范,形成行业标准。前不久 W3C 中文兴趣组也在对小程序的生态进行了规范的相关讨论,相信后续必然会朝着标准化的方向发展。


2019-07-03 19:338474

评论 1 条评论

发布
用户头像
小程序启动包括:小程序初始化、下载小程序代码包、加载业务代码包、初始化小程序首页;

请问:
1. onLaunch 在什么时候开始执行?onLaunch ~ onShow,对应以上哪个阶段呢?
2. 初始化小程序首页是指:首页 onLoad ~ onShow? 还是onLoad ~ onReady?

2019-12-03 00:13
回复
没有更多了
发现更多内容

高精度轻量级图像分割SOTA模型PP-LiteSeg重磅开源!

百度大脑

Redis主从复制集群及数据异常丢失恢复思路

jiangxl

redis'

【直播回顾】OpenHarmony知识赋能第五期第二课——成为社区达人

OpenHarmony开发者

OpenHarmony 社区贡献

web前端培训懒加载对 Web 性能的影响

@零度

前端开发 懒加载

怎么写帮助文档?产品人看过来

小炮

帮助中心

参赛必看,2022语言与智能技术竞赛赛题任务解读直播!

百度大脑

Java 邮件发送

Java 邮件 4月月更

一文搞明白Redis中两种持久化机制RDB和AOF

jiangxl

redis'

了解HTTP的基本历史及知识

CRMEB

美好教育,无处不在 | 拓维信息携手开鸿智谷重磅发布教育在鸿OS发行版

拓维信息

操作系统 OpenHarmony OpenHarmony 3.1 Release

新冠疫情防控背后有哪些鲜为人知的技术?

DS小龙哥

4月月更

密码基础设施提供商三未信安加入龙蜥社区

OpenAnolis小助手

合作伙伴 龙蜥社区 CLA 三未信安 密码基础设施

关于「应变力」这个超能力|ONES 人物

万事ONES

管理

百度天工AIoT打造农业种植方案,用数字经济助力建设农业新模式

百度大脑

OpenHarmony技术日探讨教育发展,聚焦开源人才培养

OpenHarmony开发者

OpenHarmony

深度剖析OpenHarmony应用/服务的逻辑结构

Anna

OpenHarmony

OpenHarmony 设备开发环境搭建 / 源码获取 / 编译 / 烧录

Anna

OpenHarmony

一站式内容创作助手 智能创作平台生成正式商用

百度大脑

Android C++系列:函数知识知多少

轻口味

c++ android 4月月更

赛事解析|乒乓球时序动作定位大赛亚军方案分享

百度大脑

pinpoint插件开发之一:牛刀小试,调整gson插件

程序员欣宸

Java web 4月月更 Pinpoint

浅谈C#字符串构建利器StringBuilder

yi念之间

C# StringBuilder

浅谈云上攻防——Etcd风险剖析

腾讯安全云鼎实验室

安全攻防 网络安全

某意大利小哥,竟靠一个缓存中间件直接封神?

沉默王二

redis

「质量三人行之不止测试」直播问题解答

BY林子

软件测试 职业发展 质量赋能 测试转型 质量内建

《SQL必知必会》读书笔记

懒时小窝

数据库 sql

金蝶云·苍穹峰会震撼来袭

金蝶云·苍穹

Java 如何从一个 List 中随机获得元素

HoneyMoose

浅谈C#可变参数params

yi念之间

C# params

OpenHarmony应用开发之全局配置参数解析

Anna

OpenHarmony

OpenHarmony啃论文计划-elf文件格式介绍

Anna

OpenHarmony

启动耗时降低30%!腾讯在线教育小程序开发实践与优化_语言 & 开发_陈超_InfoQ精选文章