收藏
回答

聊天功能频繁刷新导致页面卡顿

框架类型 问题类型 API/组件名称 终端类型 微信版本 基础库版本
小程序 Bug setData 客户端 6.7.2 2.3.0



我们直播间有聊天和送礼的功能,

当有大量的聊天消息短时间出现时,会导致整个直播间卡顿,下面的功能按钮点击无反应,过一段时间才有反应,且十分卡顿


page({
 
    data: {
 
        chatMsg: [] // 存放聊天消息的数组
 
    }
 
})


目前我的做法是:


添加消息到data中的消息数组时,setData只更新新消息部分:

this.setData({
       [`chatMsg[${len}]`]: val
})


而setData的频率也有限制,在有大量消息过来的时候,我这边限制1s才setData一次,但这一次setData的数据可能有几十条:

this.setData({
       [`chatMsg[3]`]: val,
       [`chatMsg[4]`]: val,
       [`chatMsg[5]`]: val,
       [`chatMsg[6]`]: val,
       [`chatMsg[7]`]: val,
       [`chatMsg[8]`]: val,
                 .
                 .
                 .
      [`chatMsg[99]`]: val
})


在这些大量消息涌进来的时候,我点击直播间底部的聊天按钮,礼物按钮都是点击无反应。等这些大量消息停止涌入时,我的点击才有反应


请教下官方和其他朋友们,如何优化这部分呢?做到即使大量消息进来,也不会把直播间卡死操作不了


待确定的方案:

  1. 需不需要在data的chatMsg已经有大量数据后,删除一部分早期的数据?

    因为我增加数据是单条的setData,不是setData整个数组,是不是代表逻辑层只会传变化的数据过去渲染,这样即使早期有很多数据也不影响?

  2. ....

回答关注问题邀请回答
收藏

7 个回答

  • 喵里
    喵里
    2019-04-24

    这个问题有没有最后的解决方案了?

    2019-04-24
    有用
    回复
  • NelsonYao
    NelsonYao
    2018-11-11

    你好 可以咨询下这个互动聊天是socket还是IM实现

    2018-11-11
    有用
    回复
  • 匿名
    匿名
    2018-10-23

    分享一下吱呀语音直播小程序的一些优化经验:

    1、评论只保持最新的若干条(我是200),每次concat新消息的时候,把超出的旧item丢弃;

    2、做好节流:缓存最新列表,在内存中可以随时concat得到最新列表,但是控制好setData的频率,比如固定1s执行一次;

    3、合并setData操作,你页面肯定不止评论需要调用setData,建议把同一时刻的多个更新操作合并为一次,比如评论concat完成之后,scroll-view还要更新scroll-into-view的值,这两个可以合并;

    4、key不要用index,用id;

    5、待补充……

    做到固定的频率,控制定量的更新,肯定不会卡的,更何况我当时直播间还要实现很多特效。。。

    年前的项目了,优化做了很多而且持续在做,不过我现在已经不在那个团队,只能回想起这么多,希望有帮助。

    2018-10-23
    有用
    回复 9
    • BY
      BY
      2018-10-23

      你好,key用index和item里面的某个id值会有什么区别么?

      2018-10-23
      回复
    • 匿名
      匿名
      2018-10-23回复BY

      wx:key 的值以两种形式提供

      1. 字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。

      2. 保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:

      当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。


      唯一的id能够提高列表的渲染效率,而且有更高的复用率,index并不是不变的,新的评论加进来以后,前面因为有item被挤出去,index不一样了。

      2018-10-23
      回复
    • BY
      BY
      2018-10-23回复匿名

      你好,我这边压测1s内收到100条消息,循环1000次时,我这边的处理是

      1. 把1s内收到的消息暂存消息队列

      2. 1s后取最新的6条消息,setData到消息数组,即页面只显示6条数据

      3. wx:key用的msg内的id,非index

      4. 场景是在直播间内,使用cover-view标签


      测试结果:

      IOS不卡

      安卓测了7部手机,有4部不卡,其余3部卡顿闪动,甚至消息区空白(还没来及渲染出来下一波消息又setData进来)

      2018-10-23
      回复
    • 匿名
      匿名
      2018-10-23回复BY

      你的意思是1s内只更新6条数据都来不及?这个有点说不过去吧?我猜你的实现方式可能有些问题的。

      另外,setData是一个异步操作,我建议你的下一次循环从setData的回调里开始:


      Page({
        data: {
          list: [],
        },
        onReady() {
          this.startUpdateList();
        },
        updateList(newList) {
          const that = this;
          return new Promise((res) => {
            that.setData({
              list: newList,
            }, res);
          });
        },
        startUpdateList() {
          const that = this;
          const newList = [];
          [1, 2, 3, 4, 5, 6].map(() => newList.push(Math.random()));
          this.updateList(newList)
            .then(() => {
              setTimeout(that.startUpdateList, 1000);
            });
        },
      });



      2018-10-23
      回复
    • BY
      BY
      2018-10-25回复匿名



      你好,我这边参考你的增加了异步,下一次的setData放在上一次的回调里执行,1s中setData一次,一次6, 8, 或10条(根据1s内消息的数量决定,数量越大,插入的越少),结果还是卡顿。

      gif是昨天录制的,看日志平均每秒10条消息,多的是每秒34条消息

      2018-10-25
      回复
    查看更多(4)
  • 圆。
    圆。
    2018-10-23

    可以尝试 canvas 去绘制这些消息

    2018-10-23
    有用
    回复
  • 后米米米米
    后米米米米
    2018-10-19

    建议这样,定义一个全局的数组存所有消息(这个不要setData),然后定义一个当前显示的消息数组,每次有更新就动太计算这部分内容,计算完之后再将这个setData(覆盖)进去页面中。

    因为你页面中同一时间最多只能显示一部分数据。不要往setData中放太多数据

    2018-10-19
    有用
    回复 4
    • 后米米米米
      后米米米米
      2018-10-19

      存所有消息的那个数组也可以每次计算,符合规则就清除一下前面的内容

      2018-10-19
      回复
    • BY
      BY
      2018-10-19回复后米米米米

      你好,这样也是不行的,关键是需要太频繁的setData。 我现在是ios不能滚动,安卓的聊天区可以滚动,所以用户可以看到之前的消息。

      除非都做成不滚动的,存放消息的数组最多只显示六七条信息。这样去更新的话就不会特别卡,但还是会卡一些如果太频繁更新数据(1s更新一次)

      2018-10-19
      回复
    • 后米米米米
      后米米米米
      2018-10-19回复BY

      用promise异步setData不知道有没有用,,文档也建议不要频繁setData,我没接触过也不知道怎么优化呢

      2018-10-19
      回复
    • BY
      BY
      2018-10-19回复后米米米米

      异步也是会导致频繁setData, 感觉遇到这个坑就只能把功能做的尽量小,不滚动聊天区,只显示最新的几条消息了。或者滚动也限制消息的总条数才行

      2018-10-19
      回复
  • BY
    BY
    2018-10-19

    测试了下如果把chatMsg中的早期消息进行清除,然后再setData,两者的卡顿情况时不同的。如果每次都是把chatMsg整个数组进行setData, 同时保证chatMsg数组长度最多6条,这时候来大量消息时,会好很多,可以点开下面的功能栏,但也是稍微有些卡顿延迟。

    是不是说明即使我们对数组中的某一个元素进行setData更新时,逻辑层也是把整个数组数据传到渲染层,然后渲染层也是渲染了整个数组数据?

    2018-10-19
    有用
    回复 1
    • 卢霄霄
      卢霄霄
      2018-10-19

      他会去解析你setData的整个对象

      2018-10-19
      回复
  • 卢霄霄
    卢霄霄
    2018-10-19

    慢慢显示呗。。每1秒弄成最多setData 10条

    2018-10-19
    有用
    回复 8
    • BY
      BY
      2018-10-19

      你好,试过了每秒6条最多,一样卡的不行不行的

      2018-10-19
      回复
    • 卢霄霄
      卢霄霄
      2018-10-19回复BY

      感觉是历史的消息太多了,你key设的啥呢?

      2018-10-19
      回复
    • BY
      BY
      2018-10-19回复卢霄霄

      <block wx:for="{{chatMsg}}" wx:key="index">

      key直接是index

      2018-10-19
      回复
    • 卢霄霄
      卢霄霄
      2018-10-19回复BY

      消息都在一个列表里可以滚动吗?另外,是一开始就很卡,还是说数据积累到一定程度才卡呢?

      2018-10-19
      回复
    • BY
      BY
      2018-10-19回复卢霄霄

      现在是让安卓滚动,ios因为scroll-top bug问题设置为不滚动。一开始不卡。当有大量消息短时间涌进的时候 就开始卡了,等消息涌入完,渲染完,就又不卡了

      2018-10-19
      回复
    查看更多(3)
登录 后发表内容