背景:

最近参与开发的小程序,涉及到即时消息(IM)发送的功能;

聊天界面如下,通过键盘上的【发送】按钮,触发消息发送功能

问题发现:

功能开发完毕,进入测试流程;测试工程师反馈说:

在Android手机上,在极短的时间内频繁点击键盘上的【发送】按钮,消息会重复发送;IOS上该问题不太明显

本以为是普通的防重复提交问题,于是自然想到通过设定flag/js加锁的方式解决该问题,于是开始优化代码:

项目基本代码:

wxml:

  1. <input type="text" value="{{msgValue}}" confirm-type="send" bindconfirm="sendMsg" bindinput="bindKeyInput" placeholder="请输入聊天内容" />

  

JS:

  1. bindKeyInput(e) {
  2. this.setData({
  3. msgValue: e.detail.value.replace(/^\s+|\s+$/g, "")
  4. });
  5. },
  6. sendMsg() {
  7. let self = this;
  8. let msg = self.data.msgValue;
  9. if (msg && self.data.sendMsgState) {
  10. self.data.sendMsgState = false
  11. app.globalData.nim.sendText({
  12. scene: 'p2p',
  13. to: self.data.doctorId,
  14. text: msg,
  15. done(error, msg) {
  16. if (!error) {
  17. //消息发送成功
  18. self.setData({
  19. msgValue: ''
  20. })
  21. } else {
  22. //消息发送失败
  23. wx.showToast({
  24. title: '消息发送失败,请稍后再试',
  25. icon: 'none',
  26. duration: 1500,
  27. mask: true
  28. })
  29. }
  30. }
  31. })
  32. }
  33. }

  

1# 设定flag/js加锁

  1. //在页面初始数据data中,声明“锁”: sendMsgState
  2.  
  3. data: {
  4. sendMsgState: true
  5. }
  6.  
  7. //在发送消息方法中,符合消息发送条件的时候,把sendMsgState的值置为false;
  8. //并在消息发送成功之后,将消息发送框的value置空的之后,将sendMsgState设为true
  9. sendMsg() {
  10. let self = this;
  11. let msg = self.data.msgValue;
  12. if (msg && self.data.sendMsgState) {
  13. self.data.sendMsgState = false
  14. app.globalData.nim.sendText({
  15. scene: 'p2p',
  16. to: self.data.doctorId,
  17. text: msg,
  18. done(error, msg) {
  19. if (!error) {
  20. //消息发送成功,置空输入框;然后把sendMsgState重新设置为true
  21. self.setData({
  22. msgValue: ''
  23. }, () => {
  24. self.data.sendMsgState = true
  25. })
  26. } else {
  27. //消息发送失败
  28. wx.showToast({
  29. title: '消息发送失败,请稍后再试',
  30. icon: 'none',
  31. duration: 1500,
  32. mask: true
  33. })
  34. }
  35. }
  36. })
  37. }
  38. }

  

测试结果:

Android手机上依然存在该问题,且很容易复现。

分析原因:

在极短的时间内,频繁点击键盘上的发送按钮;此时:锁(sendMsgState)还没来得及置为false,发送内容输入框的值还没有被清空;

但发送事件已经被有效触发多次,导致了发送消息的重复。

2# 在方案一设定flag/js加锁的基础上,增加连续点击按钮事件间隔少于1s,或者连续两次发送内容相同都停止发送的补充规则

    2.1:增加连续点击按钮事件间隔少于1s

经验证:正常的消息发送使用流程,连续两次的消息发送间隔都是超过1s的;间隔小于1s的行为,可判定为重复提交:

具体做法:

步骤一:在data中注册lastSendTime,设置值为空;触发发送事件sendMsg的时候,把当前时间保存到变量currentTime;

     步骤二:判断当前时间currentTime与上次发送时间的差值是否小于1000;如果是,则发送事件连续触发时间短于1s,停止发送;

步骤三:消息发送成功之后,在置空内容输入框的setData回调方法中,将lastSendTime的值更新为:currentTime;

 

   2.2:如果当前发送的消息内容和上一次保存在data中的msgValue相同,则可判断连续两次消息重复

因为每次发送成功,data中msg都会被置空;而内容为空的时候,又是不允许发送的;

所以,在短时间内,如果当前发送的消息内容和上一次保存在data中的msgValue相同,则可判断连续两次消息重复

最终优化方案:

  1. sendMsg() {
  2. let self = this;
  3. let msg = self.data.msgValue;
  4. // 防止两次点击操作间隔太快
  5. let currentTime = new Date();
  6. if ((currentTime - this.data.lastSendTime < 1000) || (msg === self.data.msg)) {
  7. //发送事件连续触发时间短于1s,或连续两次发送内容相同,则返回
  8. return;
  9. }
  10. if (msg && self.data.sendMsgState) {
  11. self.data.sendMsgState = false
  12. app.globalData.nim.sendText({
  13. scene: 'p2p',
  14. to: self.data.doctorId,
  15. text: msg,
  16. done(error, msg) {
  17. if (!error) {
  18. self.setData({
  19. msgValue: ''
  20. }, () => {
  21. self.data.sendMsgState = true
  22. self.data.lastSendTime = currentTime
  23. })
  24. } else {
  25. //消息发送失败
  26. wx.showToast({
  27. title: '消息发送失败,请稍后再试',
  28. icon: 'none',
  29. duration: 1500,
  30. mask: true
  31. })
  32. }
  33. }
  34. })
  35. }
  36. }

  

综上所述:

在单一的flag/js加锁无效的情况下;通过添加额外的规则补充校验,最终方案如下:

 
在发送内容msg有效及flag/js锁为true的基础上;
发送事件sendMsg连续两次触发时间间隔大于或等于1s,及连续两次发送内容不相同的情况下,才允许消息被发送;
 

 最终测试结果:无论是Android,还是IOS都可以正常发送消息,无消息重复发送情况发生了

 

小程序:前端防止用户重复提交&即时消息(IM)重复发送问题解决的更多相关文章

  1. 微信小程序,前端大梦想(六)

    微信小程序,前端大梦想(六) 微信小程序之联合百度API实现定位 定位功能对于我们都不陌生,在移动端的应用中更是不可或缺的功能,小程序中也提供了对应的API帮助我们完成定位的实现,但是目前小程序的定位 ...

  2. 1_python小程序之实现用户的注册登陆验证功能

    python小程序之实现用户的注册登陆验证功能 程序扼要简述:  一.程序流程:1.程序开始2.判断本地文件/数据库是否已存在用户信息,存在则跳转到登陆,否则跳转到注册,注册成功后后跳转到登陆3.判断 ...

  3. 关于微信小程序前端Canvas组件教程

    关于微信小程序前端Canvas组件教程 微信小程序Canvas接口函数 ​ 上述为微信小程序Canvas的内部接口,通过熟练使用Canvas,即可画出较为美观的前端页面.下面是使用微信小程序画图的一些 ...

  4. 微信小程序前端与myeclipse的数据交换过程(SSH)

    这是我个人探究微信小程序前端与后端之间的数据交换的过程,再结合个人所学的SSH框架, 编程工具用myEclipse2014工具.当然,前提是后台的项目要部署到tomcat服务器上才行, 然后总结了从后 ...

  5. [重要更新]微信小程序登录、用户信息相关接口调整:使用 wx.getUserProfile 取代 wx.getUserInfo

    2021年2月24日,微信官方团队发布了一个调整通知:<小程序登录.用户信息相关接口调整说明>,公告明确从4月13日起,所有发布的小程序将无法使用 wx.getUserInfo 接口(JS ...

  6. 微信小程序之获取用户位置权限(拒绝后提醒)

    微信小程序获取用户当前位置有三个方式: 1. wx.getLocation(多与wx.openLocation一起用) 获取当前的精度.纬度.速度.不需要授权.当type设置为gcj02 返回可用于w ...

  7. 小程序获取微信用户的openid

    小程序获取微信用户的openid //index.js //获取应用实例 const app = getApp() Page({ globalData: { appid: '11121221a89e0 ...

  8. 微信小程序开发——小程序API获取用户位置及异常流处理完整示例

    前言: 小程序需要添加一个定位功能,主要的就是获取用户位置的经纬度,然后根据用户经纬度进行一些判断操作. 在小程序提供的Api中,获取用户定位信息的主要Api是 wx.getLocation(obj) ...

  9. 微信小程序前端页面书写

    微信小程序前端页面书写 WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件.事件系统,可以构建出页面的结构. 一.数据绑定 1. 普通写法 <view ...

随机推荐

  1. 解决:惠普HP LaserJet Pro M126a MFP 驱动 安装失败,及其它同类打印机失败问题

    注意:如果在 Windows XP 系统下安装出错,请先安装WindowsXP KB971276-v3补丁后再安装装驱动. 下载地址:http://www.dyjqd.com/soft/KB97127 ...

  2. C# FormClosing FormClosed 区别详解

    FormClosing事件 在窗体关闭时,FormClosing事件发生.此事件会得到处理.从而释放与窗体相关的所有资源. 如果取消此事件,则窗体仍然保持打开状态. 当窗体显示为模式对话框时,单击“关 ...

  3. Oracle数据库的导入和导出

    Oracle数据库的导入和导出,是一项重要的的技术活,不但解决了数据库的导入导出,更方便快捷的获得数据. 使用imp和exp导入导出数据 使用exp导出数据 存放目录为\ORACLE_HOME\BIN ...

  4. c#日期计算

    /// <summary> /// 计算日期的间隔(静态类) /// </summary> public static class dateTimeDiff { /// < ...

  5. https://blog.csdn.net/cddcj/article/details/52193932

    https://blog.csdn.net/cddcj/article/details/52193932 兼容性

  6. python中*的用法

    在python中,很多情况下会用到*,下面举一些例子来说明*的用法 1.数字计算中,*代表乘法,**代表求幂 print('2乘以3值为:%s'%(2*3)) print('2的3次方值为:%s'%( ...

  7. MySQL基础命令小结

    数据库授权登录[root@localhost ~]# mysql -uroot -p123456mysql> grant select,lock tables on auth.* to 'adm ...

  8. PAT_A1143#Lowest Common Ancestor

    Source: PAT A1143 Lowest Common Ancestor (30 分) Description: The lowest common ancestor (LCA) of two ...

  9. PAT_A1105#Spiral Matrix

    Source: PAT A1105 Spiral Matrix (25 分) Description: This time your job is to fill a sequence of N po ...

  10. Pytorch基础(5)——批数据训练

    一.知识点: 相关包:torch.utils.data import torch import torch.utils.data as Data 包装数据类:TensorDataset [包装数据和目 ...