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

摘要:
error){//消息发送成功,置空输入框;然后把sendMsgState重新设置为trueself.setData}else{//消息发送失败wx.showToast}}})}}测试结果:Android手机上依然存在该问题,且很容易复现。

背景:

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

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

小程序:前端防止用户重复提交&即时消息(IM)重复发送问题解决第1张

问题发现:

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

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

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

项目基本代码:

wxml:

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

JS:

  bindKeyInput(e) {
        this.setData({
            msgValue: e.detail.value.replace(/^s+|s+$/g, "")
        });
    },
    sendMsg() {
        let self = this;
        let msg = self.data.msgValue;
        if (msg && self.data.sendMsgState) {
            self.data.sendMsgState = false
            app.globalData.nim.sendText({
                scene: 'p2p',
                to: self.data.doctorId,
                text: msg,
                done(error, msg) {
                    if (!error) {
                        //消息发送成功
                        self.setData({
                            msgValue: ''
                        })
                    } else {
                        //消息发送失败
                        wx.showToast({
                            title: '消息发送失败,请稍后再试',
                            icon: 'none',
                            duration: 1500,
                            mask: true
                        })
                    }
                }
            })
        }
    }

1#设定flag/js加锁

//在页面初始数据data中,声明“锁”: sendMsgState

data: {
    sendMsgState: true
}

//在发送消息方法中,符合消息发送条件的时候,把sendMsgState的值置为false;
//并在消息发送成功之后,将消息发送框的value置空的之后,将sendMsgState设为true
sendMsg() {
        let self = this;
        let msg = self.data.msgValue;
        if (msg && self.data.sendMsgState) {
            self.data.sendMsgState = false
            app.globalData.nim.sendText({
                scene: 'p2p',
                to: self.data.doctorId,
                text: msg,
                done(error, msg) {
                    if (!error) {
                        //消息发送成功,置空输入框;然后把sendMsgState重新设置为true
                        self.setData({
                            msgValue: ''
                        }, () => {
                            self.data.sendMsgState = true
                        })
                    } else {
                        //消息发送失败
                        wx.showToast({
                            title: '消息发送失败,请稍后再试',
                            icon: 'none',
                            duration: 1500,
                            mask: true
                        })
                    }
                }
            })
        }
    }

测试结果:

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相同,则可判断连续两次消息重复

最终优化方案:

   sendMsg() {
        let self = this;
        let msg = self.data.msgValue;
        // 防止两次点击操作间隔太快
        let currentTime = new Date();
        if ((currentTime - this.data.lastSendTime < 1000) || (msg === self.data.msg)) {
            //发送事件连续触发时间短于1s,或连续两次发送内容相同,则返回
            return;
        }
        if (msg && self.data.sendMsgState) {
            self.data.sendMsgState = false
            app.globalData.nim.sendText({
                scene: 'p2p',
                to: self.data.doctorId,
                text: msg,
                done(error, msg) {
                    if (!error) {
                        self.setData({
                            msgValue: ''
                        }, () => {
                            self.data.sendMsgState = true
                            self.data.lastSendTime = currentTime
                        })
                    } else {
                        //消息发送失败
                        wx.showToast({
                            title: '消息发送失败,请稍后再试',
                            icon: 'none',
                            duration: 1500,
                            mask: true
                        })
                    }
                }
            })
        }
    }

综上所述:

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

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

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

免责声明:文章转载自《小程序:前端防止用户重复提交&amp;amp;即时消息(IM)重复发送问题解决》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇rabbitmq trace 日志的使用以及其疑惑之处Dapr组件(Components)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

SAP-Function

[转]sap函数大全 ********SAP中常用函数 函数名 描述SD_VBAP_READ_WITH_VBELN 根据销售订单读取表vbap中的信息EDIT_LINES 把READ_TEXT返回的LINES中的行按照TDFORMAT=“*”重新组织VIEW_MAINTENANCE_CALL 维护表视图 函数名 描述DY_GET_FOCUS 获得屏幕焦点D...

Web Worker 使用教程

Web Worker 使用教程 一、概述 JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。随着电脑计算能力的增强,尤其是多核 CPU 的出现,单线程带来很大的不便,无法充分发挥计算机的计算能力。 Web Worker 的作用,就是为 JavaScript 创造多...

HTTP CHUNKED C实现

C语言不像C#一样有很多很多高度的模块化的东西可以使用,在通讯过程中特别是与http相关的通讯过程中可能要对网站返回的数据做一定处理,而且有不少网站的回应是强制性的,例如向网站请求deflate有个能会返回的是gzip的数据。在这过程中与web特性有关的,在服务器构造消息之前可能并不知道或者不方便知道消息的长度,于是就会将消息分为一段段进行传送。 例如如下...

layui 学习笔记(四) 复杂表头前台Excel导出

layui - excel 复杂表头导出- 第三方插件实现 参考:https://fly.layui.com/extend/excel/演示:http://excel.wj2015.com/    http://excel.wj2015.com/_book/docs/%E5%87%BD%E6%95%B0%E5%88%97%E8%A1%A8/%E5%AF%B...

Android——bootchart

bootchart:android原生自带的开机性能查看机制。通过收集android开机过程中的各种log数据,终于能够图表的形式展现各个进程在开机过程中的性能。(博客不能断…) 撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/45933943本文来自 【jscese】的博客。 编译boo...

nonebot 源码阅读笔记

前言 nonebot 是一个 QQ 消息机器人框架,它的一些实现机制,值得参考。 nonebot NoneBot 初始化(配置加载) 阅读 nonebot 文档,第一个示例如下: import nonebot if __name__ == '__main__': nonebot.init() nonebot.load_builtin_pl...