问题:
调用限流 ,没走闭包的函数: checkBalanceReq()
loadsh.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; // 在函数开头判断标记是否为true,不为true则return
canRun = false; // 立即设置为false
setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
fn.apply(context, arguments);
// 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
canRun = true;
}, 500);
};
}
module.exports = {
throttle: throttle,
}
页面调用:点击加减号调用限流方法
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) {
}
});
为什么??
在浏览器HTML ok
<!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
// btn.onclick = function () {
// count++;
// document.querySelector('span').innerText = count
// }
// 简单实现-settimeout
function throttle(fn, interval, context) {
let canRun = true; // 通过闭包保存一个标记
interval = interval | 500
return function () {
console.log(">>interval=" + interval, context)
if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
canRun = false; // 立即设置为false
setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
fn.apply(this, arguments);
// 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
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个括号()(),返回闭包函数
// 简单实现-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了。
const {throttle} = require('../../utils/loadshMy')
var balanceCallFn
Page({
data: {
test: "测试",
OrderCount: 0,
list: [1, 2, 3, 4, 5, 6, 7, 8, 9]
},
onswitch(e) {
console.log(e)
this.setData({
showinput: true,
focus: true,
current: e.target.dataset.index,
})
},
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" data-index="{{index}}">-</text>
<text type="number" class="number" bindtap="onswitch" wx:if="{{!showinput}}">{{OrderCount}}</text>
<input type="number" class="number" >{{OrderCount}}</input>
<text class="add" bindtap="onChangeNums">+</text>
最终,总算执行到回调的方法log OK ,且多次点击也很限流了。 花一个上午时间调试这个问题,还是闭包知识不牢固。