问题:
调用限流 ,没走闭包的函数: checkBalanceReq()
业务逻辑:
1.限流函数:loadshMy.js
// 限流
const throttle = (fn, context, interval) => {
console.log(">>>>cmm throttle", context, interval)
let canRun = true; // 通过闭包保存一个标记
if (typeof fn != "function") {
console.log("fn 变量需要是函数")
return;
}
interval = interval ? interval : 500
console.log(">>开始return", interval)
return function (e) {//匿名函数
console.log(">>限流return")
let args = arguments
console.log(">>>args", args)
if (!canRun) return;
canRun = false; // 立即设置为false
setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
fn.apply(context, arguments);
canRun = true;
}, 500);
};
}
module.exports = {
throttle: throttle,
}
2.页面调用:点击加减号调用限流方法,
const {throttle} = require("../../utils/loadshMy");
Page({
data: {
test: "测试",
OrderCount: 0,
list: [1, 2, 3, 4, 5, 6, 7, 8, 9]
},
onChangeNums(e) { //点击加号减号触发事件
if (e.target.dataset.add) {
this.setData({
OrderCount: this.data.OrderCount + 2
})
} else {
this.setData({
OrderCount: this.data.OrderCount - 2
})
}
console.log(">>>开始throtthle", this)
throttle.apply(this, [this.checkBalanceReq, this, 660])
},
checkBalanceReq() {
console.log(">>||----------------执行余额查询")
}
onLoad: function (options) {
}
});
运行结果是:怎么都调不到checkBalanceReq()这个方法。为什么??
3.测试:在浏览器HTML运行差不多的逻辑,运行回调是 OK的, WHY?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>节流</title>
</head>
<body>
<div>
<h1>节流:请输入要搜索的内容 <span>0</span></h1>
<button type="button">点击加1</button>
<script>
//节流:在规定时间内, 只触发或者只执行一次对应函数,减少函数的执行。即:频繁触发改为少量触发
let btn = document.querySelector('button')
var count = 0
function throttle(fn, interval, context) {
let canRun = true;
interval = interval | 500
return function () {
console.log(">>interval=" + interval, context)
if (!canRun) return;
canRun = false;
setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
fn.apply(this, arguments);
canRun = true;
}, interval);
};
}
function sayHi(e) {
console.log(e.target.innerWidth, e.target.innerHeight);
console.log(count + 12)
pr()
}
function pr() {
console.log(count++)
}
window.addEventListener('resize', throttle(sayHi));
btn.addEventListener('click', throttle(sayHi, 500, this));
</script>
</div>
</body>
</html>
解决:
发现返回的闭包在使用立即执行,给return的函数用2个括号封装起来()()
因为return的是function,外部访问的时候必须加上括号,不然得到的是function本身的内容,但不执行。如果要得到return后的函数,就是要得到throttle()(),而不是throttle(), 所以return的函数必须加上括号。
会立即执行回调函数的代码:
loadsh.js
// 简单实现-settimeout
const throttle = (fn, context, interval) => {
console.log(">>>>|--------15 ------- cmm throttle", context, fn)
let canRun = true; // 通过闭包保存一个标记
if (typeof fn != "function") {
console.log("fn 变量需要是函数")
return;
}
interval = interval | 500
console.log(interval)
return (function () {//匿名函数
console.log(">>限流return")
let args = arguments
console.log(">>>args", args)
if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
canRun = false; // 立即设置为false
setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
fn.apply(context, arguments);
// 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
canRun = true;
}, interval);
})();
}
module.exports = {
throttle: throttle
}
新问题2:
以上业务代码能执行到回调函数:checkBalanceReq(),但是限流效果没有达到,每次一点击按钮,都会执行到回调函数。
问题分析:
wxml页面调用的地方,每次都是一个新的变量,需要做成保存唯一的封包函数。
throttle不要直接用2个括号()(), 返回闭包函数用一个当前页面的全局变量存起来。
最后完整的OK代码:
// 简单实现-settimeout
const throttle = (fn, context, interval) => {
console.log(">>>>|--------15 ------- cmm throttle", context, fn)
let canRun = true; // 通过闭包保存一个标记
if (typeof fn != "function") {
console.log("fn 变量需要是函数")
return;
}
interval = interval | 500
console.log(interval)
return function () {//匿名函数
console.log(">>限流return")
let args = arguments
console.log(">>>args", args)
if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
canRun = false; // 立即设置为false
setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
fn.apply(context, arguments);
// 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
canRun = true;
}, interval);
};
}
module.exports = {
throttle: throttle
}
小程序页面对应 js: 页面增加一个变量balanceCallFn,来存储返回的封包函数,不为空的情况直接执行,就不会每次冲掉timer了。
(throttle.apply()让调用内部this指向当前页面this)
.js
const {throttle} = require('../../utils/loadshMy')
var balanceCallFn
Page({
data: {
test: "测试",
OrderCount: 0,
list: [1, 2, 3, 4, 5, 6, 7, 8, 9]
},
onChangeNums(e) { //点击加号减号触发事件
if (e.target.dataset.add) {
this.setData({
OrderCount: this.data.OrderCount + 2
})
} else {
this.setData({
OrderCount: this.data.OrderCount - 2
})
}
console.log(">>>开始throtthle", this)
if(!balanceCallFn){
balanceCallFn=throttle.apply(this, [this.checkBalanceReq, this, 660])
}
balanceCallFn();
},
checkBalanceReq() {
console.log(">>||----------------执行余额查询")
},
bindinputnum(e) {
console.log(">>>失去点时")
this.setData({
showinput: false
})
},
onLoad: function (options) {
}
});
.wxml
<text class="minus" data-minus bindtap="onChangeNums>-</text>
<input type="number" class="number" >{{OrderCount}}</input>
<text class="add" data-add bindtap="onChangeNums">+</text>
最终,总算执行到回调的方法log OK ,且多次点击也很限流了。 花一个上午时间调试这个问题,还是闭包知识不牢固。