在使用小程序的时候,如果点击很多次就会有可能导致页面假死甚至崩溃。那么微信小程序如何避免多次点击呢?小编带来了解决办法,希望能够对大家有所帮助。

最近听产品经理常说,用户点击某个小程序按钮多次,后台还没处理完导致多笔记录生成,我们需要在用户点击后跳转到一个新的页面,其实这根本不是跳页问题,是程序问题,所以我们要尝试着避免多次点击。

以前偷懒的时候,在前端我们可能会这么处理:

var getUserDataFlag = false;
getUserData() {
if (getDataFlag) {
return;
}
getDataFlag = true;
$.ajax({
url: '/xxx/getUser',
success: () {
getUserData = false;
//todo
},
error: () {
getUserData = false;
}
})
}
//当小程序接口很多的时候,我们的代码就变成这样
var getUserAssetFlag = true;
getUserAsset() {
if (getDataFlag) {
return;
}
getDataFlag = true;
$.ajax({
url: '/xxx/getUserAsset',
success: () {
getUserAssetFlag = false;
//todo
},
error: () {
getUserAssetFlag = false;
}
})
}

上面的例子你会发现,当接口越来越多,维护请求状态的变量将会越来越多,并且当存在依赖时,维护成本更高,也更容易出错。

如何优雅地解决这样的问题,其实小程序封装一下请求就能简单又能自动地处理这个问题。

下面我们以微信小程序请求后台数据为例解说:

import {isObject} from './util'
let Promise = require('../libs/bluebird.min')
let requestList = {} //api请求记录
// 将当前请求的api记录起来
export addRequestKey (key) {
requestList[key] = true
}
// 将请求完成的api从记录中移除
export removeRequestKey (key) {
requestList[key]
}
//当前请求的api是否已有记录
export hitRequestKey (key) {
return requestList[key]
}
// 获取串行请求的key,方便记录
export getLockRequestKey (data) {
if (!isObject(data)) {
return data
}
let ajaxKey = 'lockRequestKey:'
try {
ajaxKey += JSON.stringify(data)
} catch (e) {
ajaxKey += data
}
return ajaxKey
}
//根据请求的地址,请求参数组装成api请求的key,方便记录
export getRequestKey (data) {
if (!isObject(data)) {
return data
}
let ajaxKey = 'Method: ' + data.method + ',Url: ' + data.url + ',Data:'
try {
ajaxKey += JSON.stringify(data.data)
} catch (e) {
ajaxKey += data.data
}
return ajaxKey
}
//所有与服务器进行http请求的出口
export http (data) {
if (!isObject(data)) {
throw Error('ajax请求参数必须是json对象: ' + data)
}
data.method = (data.method || 'GET').toUpperCase()
//下面5行是对所有http请求做防重复请求处理,后面单独分享原理
let ajaxKey = getRequestKey(data)
if (hitRequestKey(ajaxKey)) {
throw Error('重复提交请求:' + ajaxKey)
}
addRequestKey(ajaxKey)
//bluebird包装成promisepromise api
return new Promise( (resolve, reject) {
//通过wx.request api 向服务器端发出http请求
wx.request({
url: data.url,
data: data.data,
method: data.method,
header: data.header || {'Content-Type': 'application/json'},
complete: (res) {
// 请求完成,释放记录的key,可以发起下次请求了
removeRequestKey(ajaxKey)
let statusCode = res.statusCode
if (statusCode === 200 || statusCode === 304) {
return resolve(res.data)
}
return reject(res)
}
})
})
}
//通用get请求方法
export httpGet (data) {
return http(data)
}
//通用post请求方法
export httpPost (data) {
data.method = 'POST'
return http(data)
}
// 该方法适用于串行请求的api
export lockRequest (data, fn) {
let ajaxKey = getLockRequestKey(data)
if (hitRequestKey(ajaxKey)) {
throw Error('重复提交请求:' + ajaxKey)
}
addRequestKey(ajaxKey)
return new Promise( (resolve, reject) {
fn(data)
.then( (data) {
removeRequestKey(ajaxKey)
return resolve(data)
})
.catch( (error) {
removeRequestKey(ajaxKey)
return reject(error)
})
})
}

整体思路就是统一所有请求的入口,然后以小程序API请求的地址,参数,请求类型(get,post)等组装为唯一key缓存起来。这样就能知道某个请求的完成状态,当第二个相同的请求过来时,我们可以根据上一次的状态来判断下一步的操作。