小程序:前端防止用户重复提交&即时消息(IM)重复发送问题解决
背景:
最近参与开发的小程序,涉及到即时消息(IM)发送的功能;
聊天界面如下,通过键盘上的【发送】按钮,触发消息发送功能
问题发现:
功能开发完毕,进入测试流程;测试工程师反馈说:
在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都可以正常发送消息,无消息重复发送情况发生了
小程序:前端防止用户重复提交&即时消息(IM)重复发送问题解决的更多相关文章
- 微信小程序,前端大梦想(六)
微信小程序,前端大梦想(六) 微信小程序之联合百度API实现定位 定位功能对于我们都不陌生,在移动端的应用中更是不可或缺的功能,小程序中也提供了对应的API帮助我们完成定位的实现,但是目前小程序的定位 ...
- 1_python小程序之实现用户的注册登陆验证功能
python小程序之实现用户的注册登陆验证功能 程序扼要简述: 一.程序流程:1.程序开始2.判断本地文件/数据库是否已存在用户信息,存在则跳转到登陆,否则跳转到注册,注册成功后后跳转到登陆3.判断 ...
- 关于微信小程序前端Canvas组件教程
关于微信小程序前端Canvas组件教程 微信小程序Canvas接口函数 上述为微信小程序Canvas的内部接口,通过熟练使用Canvas,即可画出较为美观的前端页面.下面是使用微信小程序画图的一些 ...
- 微信小程序前端与myeclipse的数据交换过程(SSH)
这是我个人探究微信小程序前端与后端之间的数据交换的过程,再结合个人所学的SSH框架, 编程工具用myEclipse2014工具.当然,前提是后台的项目要部署到tomcat服务器上才行, 然后总结了从后 ...
- [重要更新]微信小程序登录、用户信息相关接口调整:使用 wx.getUserProfile 取代 wx.getUserInfo
2021年2月24日,微信官方团队发布了一个调整通知:<小程序登录.用户信息相关接口调整说明>,公告明确从4月13日起,所有发布的小程序将无法使用 wx.getUserInfo 接口(JS ...
- 微信小程序之获取用户位置权限(拒绝后提醒)
微信小程序获取用户当前位置有三个方式: 1. wx.getLocation(多与wx.openLocation一起用) 获取当前的精度.纬度.速度.不需要授权.当type设置为gcj02 返回可用于w ...
- 小程序获取微信用户的openid
小程序获取微信用户的openid //index.js //获取应用实例 const app = getApp() Page({ globalData: { appid: '11121221a89e0 ...
- 微信小程序开发——小程序API获取用户位置及异常流处理完整示例
前言: 小程序需要添加一个定位功能,主要的就是获取用户位置的经纬度,然后根据用户经纬度进行一些判断操作. 在小程序提供的Api中,获取用户定位信息的主要Api是 wx.getLocation(obj) ...
- 微信小程序前端页面书写
微信小程序前端页面书写 WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件.事件系统,可以构建出页面的结构. 一.数据绑定 1. 普通写法 <view ...
随机推荐
- ★Java面向对象(一)——————————基本概念
package boll; /* 用Java语言对现实生活中的事物进行描述. 通过类的形式来体现, 怎么描述呢? 对于事物的描述通常只有两个方面,一个是属性,一个是行为. 只要明确该事物的行为和属性并 ...
- MOOC推荐及三门基础学科
top1:学堂在线 http://www.xuetangx.com/ top2:网易云课堂 http://study.163.com/ top3:coursera https://www.course ...
- API接口测试用例编写规则(转载)
API接口测试用例编写规则 (1)必需参数覆盖.对于接口的参数,接口文档一般都会说明哪些儿是必需的,哪儿是非必需的.对于必需的参数,一定要测试传参数和不传参数接口是否报错? (2)必需的参数各种情况覆 ...
- 微信小程序中的iPhone X适配问题
微信小程序中的iPhone X适配问题 小程序中下方的导航会被iPhone X下面的那条黑线盖住[微笑脸],所以要专门为了iPhone X做样式上的适配[微笑脸] wx.getSystemInfo({ ...
- react-draft-wysiwyg富文本
import { EditorState, convertToRaw } from 'draft-js'; import { Editor } from 'react-draft-wysiwyg' ...
- Js 删除前弹出确认框
<td align="center" valign="middle" class="black3"> <c:if test ...
- vue点击实现 路由的跳转
点击按钮实现路由的跳转 <div @click="gotoMenu">按钮</div> 实现跳转 methods: { gotoMenu(){ //跳转到上 ...
- PAT_A1146#Topological Order
Source: PAT A1146 Topological Order (25 分) Description: This is a problem given in the Graduate Entr ...
- 【剑指Offer】36、两个链表的第一个公共结点
题目描述: 输入两个链表,找出它们的第一个公共结点. 解题思路: 本题首先可以很直观的想到蛮力法,即对链表1(假设长度为m)的每一个结点,遍历链表2(假设长度为n),找有没有与其相同的 ...
- 51nod1117 聪明的木匠【贪心+优先队列】
一位老木匠需要将一根长的木棒切成N段.每段的长度分别为L1,L2,......,LN(1 <= L1,L2,-,LN <= 1000,且均为整数)个长度单位.我们认为切割时仅在整数点处切且 ...