某年腾讯互动娱乐市场体系年会上,团队制作了一个主要提供线下服务的微信小程序,参与了员工大会、聚餐等多个环节。用到的技术有:公司智能网关+身份判定、小程序导航、小程序云功能、云数据库、云存储、多场景实时数据库、小程序支付能力、内嵌H5小游戏、小程序红包能力等。
背景
这款小程序是TIEM市场体系年会的辅助互动工具,此次年会共有1200余名员工和数十位外部嘉宾参加,年会分为下午员工大会、红毯、晚宴表演等环节,小程序具体功能及对应核心技术如下:
智能网关判断人员是员工还是嘉宾。实时数据库更新发布会+红毯+晚宴节目的进度。在直播辩论环节,实时数据库显示投票情况,并实时呈现在舞台侧屏上(类似《奇葩说》)。实时数据库更新红毯流程(部门各团队排队入场流程)。精彩场景以瀑布流形式存入云端,为员工提供上传预览照片的功能。在晚宴节目中,员工可以对自己的表现给予无偿支持和有偿打赏,通过实时数据库呈现在小程序和舞台侧屏中。各舞台屏的网页抽奖结果通过HTTP API同步到小程序云数据库。晚宴期间,整个会场播放H5互动小游戏,每个人的游戏成绩通过HTTP API汇总在其选择的桌位总分中。 桌边争夺冠军,前三名的桌号和总分通过实时数据库能力呈现在舞台屏幕上。每一个体验过游戏的玩家,回到小程序游戏大厅后,都会被小程序红包能力分配一份现金红包。
云开发
开发者们第一次接触云开发,需要从零开始搭建一个云应用,并在一个月内完成任务。在任务重、时间紧的双重压力下,开发者们开始担心云开发的能力。结果事实证明,小程序云开发的开箱即用、原生微信能力集成、云函数内置认证、无障碍等强大能力,对于没有后端开发经验的前端开发者来说是一个不错的选择。
实时数据库
这次要分享的是腾讯云联合微信小程序推出的能力——实时数据推送。
微信小程序提供的实时推送能力很简单,只有一个API,就是[1]。记住这个关键字,就是实时数据推送的代名词。是官方自研的能力,开箱即用,无需管理长连接,无需写服务端代码,不占用数据库连接数,简单来说就是官方的礼物。从官方云开发demo中包含的一个聊天场景可以看出,实时数据推送能力对聊天室、聊天模块等即时通讯功能有着天然的友好性,也非常适合年会小程序的“打赏后即时反馈”功能,以及小程序中的游戏大厅功能。接下来我们来说说如何应用实时数据推送能力。
应用——掌控整个年会节奏
小程序运行时,启动一个监听器,将监听到的数据变化写入当前页面的数据中,从而实现界面状态的改变。
先来一张GIF,大家可以看到,只要左侧小程序管理端有操作,右侧所有用户的小程序端都会立刻产生相应的变化:
1//业务逻辑太复杂,这里写伪代码 2//app.js 3App({ 4 loadConfig:function(){ 5 //可以把它当成是一个setInterval,设置一个ID给它,方便关闭它 6 this.globalData.adminWatch = db.collection("adminConfig").watch({ 7 onChange: function(res) { 8 let { 9 _id, 10 ...adminConfig 11 } = res.docs[0]; 12 console.log('配置改变:', adminConfig) 13 const _page = getCurrentPages(); 14 if (_page) { 15 _page[_page.length - 1].setData({ //这里很关键,把监听到的变化驱动当前界面的变化 16 adminConfig 17 }) 18 } 19 }, 20 onShow:function(){ 21 this.loadConfig() //每次唤起小程序都开启监听 22 }, 23 onHide:function(){ 24 this.globalData.adminWatch.close() //每次隐藏小程序都关闭监听 25 } 26}) 27 28//某个具体页面的比如game.xml,就可以依赖以上的adminConfig做状态判断了。 29游戏正式开始 30游戏试玩
上面说了,小程序的管理页面其实就是在修改一个叫 的文件,当小程序打开时,监控就开启了,当它发生变化时,就会驱动我们的界面随之变化。还需要设计好小程序每一个需要控制的页面,结构和逻辑都要依托于此,不然就没办法驱动这个页面的界面变化。比如下图,在管理端点击“打开小游戏入口”之后,大家的小程序界面瞬间就有了入口;点击“开始游戏”之后,大家的小程序界面瞬间就会从“开始试玩”变成“点击进入”。
通过实时数据推送,可以实时改变每个员工/嘉宾在其小程序界面的界面状态,改变员工会议晚宴计划的进度。
在你面前,甚至性能瓶颈都可能
打赏页的逻辑是,当用户打赏时,就往集合里增加一条记录。然后实时数据推送会监控整个数据变化,如果事件给了什么数据,就把数据洗出来,然后直接展示在界面上。
看上去没什么问题,测试的时候也没有问题,每次我送出一点爱心,界面上的打赏记录就会瞬间体现出我的打赏行为,一切都是那么的合理。
但其实这里面有一个很隐蔽的问题,如果不是趁着年会彩排的时候测试了一次,如果首席PM不是那么细心,遇到了这个问题,到现场的时候估计就惨了。
生存危机:很多人同时在打赏的时候,几乎每一条记录都会被发送(推送到小程序),每次都会反馈到小程序,也就是每次触发界面渲染一次。它并不是我们想象的那样,会缓存一波数据变化然后推送过来。它的反馈是如此的直接和剧烈,当用户增加一条记录时,它就推送一条,数据从入磁盘DB到从服务器推送出去,只需要5-10ms的时间。也就是说,除非这5-10ms之内,有多位用户同时添加数据,否则返回的记录就是2条。想象一下,如果每秒有10条记录反馈,那么你就要操作10次。它是异步行为,也就是说它是需要时间去执行的。 如果操作调出“立即奖励”面板(其实也算一个操作),你将面临需要在1秒10次的间隙中插入调出界面的操作,但试想一下这怎么能比设备还快呢?一旦空闲,就会被事件的反馈自动执行和占用。调出界面的操作是阻塞的,甚至没有资格排队(没有排队设置)。
如果大家都想给小费,但是又调不出小费面板,那就很尴尬了,如果涉及到收入什么的(比如这里的微信支付),那就是运营事故了。
问题已经发现并提出来了,解决起来就容易了。解决方案是:
1onChange推送过来的数据堆在一个arr变量里: 2onChange:function(res){ 3 _this.arr.push(res.doc) 4} 5然后setInterval一个函数,每秒执行一次: 6 { 7 把arr的值setData 8 然后再清空arr 9 }
用这种自然语言来描述代码不是更直观吗?这样就很难在点击调用接口的时候占用执行时间。
这里需要加个注意,有容量限制,只能监控5000条记录,比如上面的奖励数据库,设计是每增加一条奖励就增加一条记录,如果超过5000条,事件就会报错。
所以一定要注意数据库的设计,避免超过 5000 条记录!走别的通道不占用包里标注的同时连接数,但是默认监听器最大支持 个。比如我之前说的设计,只有一条记录,就算是全局的,也没什么压力。
应用程序 - 游戏大厅
游戏大厅大概是整个小程序里我花费时间最多的部分了,界面如下:
刚进入这个界面的时候你还没有入座,需要在这里选择桌号对应的桌号(主持人会读出来);如果入座之后发现自己的桌号不对,可以直接点击正确的桌号重新入座,也可以先点击离开再选择正确的桌号入座。这里面涉及到两次云函数调用,在弱网环境下可能会有1秒的延迟,如果在延迟过程中有人选择了和你相同的桌号,而这张桌子上已经有11个人了(每张桌子限制12个人),就会出现数据错误。所以这里的查询条件和方法很有讲究,经过3次半的改版,将体验优化到了大家勉强可以接受的地步。
第一次:桌位本身的设计就不合理,只是跑通整个交互,直接实现入座、离开、开始的基本目标。但是不仅性能不佳,从点击入座到界面显示需要1.5+秒。前端性能也不一致,主要体现在头像已经在桌位,但“直接开始”和“离开”按钮延迟0.5秒才显示。
第二次:优化了表结构,每张表都是固定的一张表记录,每个玩家只是这条记录里的一个字段数组里的对象。但是这个优化造成了一个bug,就是当你频繁点击“加入”其他表时,会出现多个自己的头像。也就是说一个用户可以占据多张表,这显然是不合理的。而且换表的逻辑涉及到4次云函数调用和计算,云函数计算时间约为。
第三次:对云数据库有了更深的理解后,云函数优化,换表从4次调用减少到2次。以前是先查询目标表是否满了,再插入数据;优化后,直接插入,如果插入不了就返回状态码=‘0’通知前端。避免了换表时出现多个头像的bug,避免了11个人一张桌子,2个人同时抢桌子的情况导致数据异常。云函数计算时间也缩短到小于。跳表时先把目标表加到用户的信息里,再做当前表的个人信息操作,这样就不用等待了。
第四次:优化交互,在点击加入时增加一个,避免静态等待的同时也避免了弱网情况下反复跳表造成的渲染bug。
另外,以上截图为云函数调试界面的控制台截图,由于是开发工具,耗时远大于实际在物理机上耗时,开发者可以参考该数据实现优化目标。
总结一下游戏大厅的重点优化点:
在数据表的结构设计上,最好用能预估上限的单位作为记录本身,比如表的条数;添加表的数据操作,都是使用数据库API auto- _.inc 来添加,当多个用户同时写入时,数据库会自增字段,不会出现后一个覆盖前一个的情况;如果是跳转表的话,先运行加表逻辑,再离开当前表逻辑;要有防止多次点击的设计;分区(1-30张表,31-60张表)的渲染,分区,明细都到位,没必要保留所有(1-120张表)的表;少写查询,多做查询条件的细致化;在合适的环节加入遮罩,可以避免用户行为的相互干扰。
对于这种多人参与的小程序场景,彼此之间会有交互,对即时性的要求比较高,而且还要保证数据的一致性,建议以后给自己两倍的响应时间,这样才能保证最终的实现,带来好的体验。一味的往一个方向优化,未必是一个好的解决方案。比如云函数的运行瓶颈就是回调时间至少150+ms,所以无论你如何优化体验,都不会超出这个范围;而如果加入适当的动画,屏蔽其他操作,无形中也会减少用户尴尬的等待时间,提高交互的稳定性。
数据
在长达3个小时的年会期间,小程序的PV达到了1577万,在如此短的时间内,如此大的访问量,云开发非常轻松地完成了任务。
总结
TIEM年会APP从无到有,从设计到开发再到测试,大概用了一个月的时间。团队一直忐忑不安,直到年会结束,才顺利完成了这个略超预期的任务。毕竟在回顾过程的时候,我们发现还有很多事情没有做,比如线下活动的弱网环境测试,导致有的同事在游戏厅里打不开H5游戏。
领导和同事的认可和建设性建议使整个团队受益匪浅。