js 小程序限流函数 return闭包函数执行不了

问题:

调用限流 ,没走闭包的函数:  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 ,且多次点击也很限流了。 花一个上午时间调试这个问题,还是闭包知识不牢固。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/87722.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【洛谷算法题】P1000-超级玛丽游戏【入门1顺序结构】

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P1000-超级玛丽游戏【入门1顺序结构】&#x1f30f;题目描述&#x1f30f;输入格…

10张图让你彻底理解回调函数

不知你是不是也有这样的疑惑&#xff0c;我们为什么需要回调函数这个概念呢&#xff1f;直接调用函数不就可以了&#xff1f;回调函数到底有什么作用&#xff1f;程序员到底该如何理解回调函数&#xff1f; 这篇文章就来为你解答这些问题&#xff0c;读完这篇文章后你的武器库…

Multisim中VDAC8使用

1.Multisim中VDAC8是8位DAC。双击打开后&#xff0c;数字“1”代表I/O口输入电压高于2.8V有效&#xff0c;数字“0”代表代表I/O口输入电压低于0.8V有效。 2.为控制输出电压&#xff0c;点击开关不同按钮可以调节输出值。

Docker部署MongoDB 5.0.5

1、查看目录 rootwielun:~# tree mongo mongo ├── conf │ └── mongod.conf ├── data ├── docker-compose.yml └── logrootwielun:~# cd mongo rootwielun:~/mongo# chmod 777 log2、配置docker-compose.yml rootwielun:~/mongo# cat docker-compose.yml ve…

Maven详解

文章目录 一、引言1.1 为什么需要 Maven&#xff1f;1.2 Maven 解决了哪些问题&#xff1f;1.2.1 添加第三方jar包1.2.2 jar包之间的依赖关系1.2.3 处理jar包之间的冲突1.2.4 获取第三方jar包1.2.5 将项目拆分成多个工程模块1.2.6 实现项目的分布式部署 二、介绍三、Maven 的特…

vscode+ros开发环境搭建

目录 介绍 前提 vscode安装 vscode插件安装 工作空间准备 打开vscode 创建catkin包 编写cpp代码 编译 运行 启动ros服务 监听话题 启动ros测试 介绍 ros开发是机器人开发中必不可少的工作&#xff0c;语言选择可以是c,也可以是python。工具的话&#xff0c;不能像wi…

【3ds Max】练习——制作衣柜

目录 步骤 一、制作衣柜顶部 二、制作衣柜门板 三、制作衣柜底部 四、制作柜子腿部 五、制作柜子底板 步骤 一、制作衣柜顶部 1. 首先创建一个平面&#xff0c;然后将图片素材拖入平面 2. 平面大小和图片尺寸比例保持一致 3. 单机鼠标右键&#xff0c;选择对象属性 勾选…

如何把aac转化为mp3?大家和我一起往下学习

如何把aac转化为mp3&#xff1f;aac是一种先进的音频编码格式&#xff0c;通过较小的文件大小提供出色的音质体验。然而&#xff0c;由于其相对较少的普及度&#xff0c;与MP3相比&#xff0c;兼容性稍显不足&#xff0c;有些播放器可能无法直接识别aac格式。在某种程度上&…

USB Type-C端口集成式ESD静电保护方案 安全低成本

Type-C端口是根据USB3.x和USB4协议传输数据的&#xff0c;很容易受到电气过载&#xff08;EOS&#xff09;和静电放电&#xff08;ESD&#xff09;事件的影响。由于Type-C支持随意热插拔功能&#xff0c;其内部高集成度的芯片&#xff0c;更容易受到人体静电放电的伤害和损坏。…

.netcore windows app启动webserver

创建controller: using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.Json.Serialization; using System.Threading.Tasks;namespace MyWorker.…

【linux内核】DP83867添加GMII模式支持

文章目录 修改方案前期知识为什么这么修改&#xff1f;通用寄存器 修改方案 linux 4.0内核下/drivers/net/phy/dp83867.c phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4, val);} if (phydev->interface PHY_INTERFACE_MODE_GMII){val phy_read_mmd(phydev, DP838…

微短剧赛道风口下的一站式点播解决方案

微短剧行业正风生水起。 一种全新的剧集模式正迅速崛起&#xff0c;并引起广泛关注。 从线下电影院的“巨幕”到PC端“网络大电影”&#xff0c;从“长视频”再到如今移动端1-3分钟的“微短剧”&#xff0c;影视行业在过去几年经历了一场深刻又显著的变化。 微短剧&#xff0…

网络丢包故障如何定位?如何解决?

引言 本期分享一个比较常见的网络问题--丢包。例如我们去ping一个网站&#xff0c;如果能ping通&#xff0c;且网站返回信息全面&#xff0c;则说明与网站服务器的通信是畅通的&#xff0c;如果ping不通&#xff0c;或者网站返回的信息不全等&#xff0c;则很可能是数据被丢包了…

Android OpenCV(七十五): 看看刚”转正“的条形码识别

前言 2021年,我们写过一篇《OpenCV 条码识别 Android 平台实践》,当时的条形码识别模块位于 opencv_contrib 仓库,但是 OpenCV 4.8.0 版本开始, 条形码识别模块已移动到 OpenCV 主仓库,至此我们无需自行编译即可轻松地调用条形码识别能力。 Bar code detector and decoder…

C++ Day3

目录 一、类 【1】类 【2】应用实例 练习&#xff1a; 【3】封装 二、this指针 【1】this指针的格式 【2】必须使用this指针的场合 三、类中的特殊成员函数 【1】构造函数 i&#xff09;功能 ii&#xff09;格式 iii&#xff09;构造函数的调用时机 iv&#xff09;…

面试官:策略模式有使用过吗?我:没有......

面试官&#xff1a;策略模式有使用过吗&#xff1f;我&#xff1a;没有… 何为策略模式&#xff1f; 比如在业务逻辑或程序设计中比如要实现某个功能&#xff0c;有多种方案可供我们选择。比如要压缩一个文件&#xff0c;我们既可以选择 ZIP 算法&#xff0c;也可以选择 GZIP…

【云计算】Docker特别版——前端一篇学会

docker学习 文章目录 一、下载安装docker&#xff08;一&#xff09;Windows桌面应用安装&#xff08;二&#xff09;Linux命令安装 二、windows注册登录docker三、Docker的常规操作(一)、基本的 Docker 命令(二)、镜像操作(三)、容器的配置(四)、登录远程仓库 四、镜像管理(一…

SIP桌面式对讲主机 井下通信广播sip寻呼话筒

SV-8003VP是我司的一款SIP桌面式对讲主机&#xff0c;具有10/100M以太网接口&#xff0c;配置了麦克风输入和扬声器输出&#xff0c;还配置多达22个按键和2.8英寸液晶显示屏&#xff0c;可以配合SIP服务器使用。SV-8003VP网路寻呼话筒可以通过麦克风或者本地线路输入对SIP终端进…

CLIP(Contrastive Language-Image Pre-training)

《Learning Transferable Visual Models From Natural Language Supervision》 从自然语言监督中学习可迁移的视觉模型 贡献:利用自然语言信号监督,打破了固定类别的范式。 方法简单,效果好。从文本中得到监督信号,引导视觉分类的任务。 它是一个 zero-shot 的视觉分类…

MyBatis进阶:告别SQL注入!MyBatis分页与特殊字符的正确使用方式

目录 引言 一、使用正确的方式实现分页 1.1.什么是分页 1.2.MyBatis中的分页实现方式 1.3.避免SQL注入的技巧 二、特殊字符的正确使用方式 2.1.什么是特殊字符 2.2.特殊字符在SQL查询中的作用 2.3.如何避免特殊字符引起的问题 2.3.1.使用CDATA区段 2.3.2.使用实体引…