当前位置 : 主页 > 网络编程 > JavaScript >

JS按钮连击和接口调用频率限制防止客户爆仓

来源:互联网 收集:自由互联 发布时间:2023-02-08
目录 背景 节流是什么 如何节流 不使用节流 使用节流之后 模板 示例 结束语 背景 这个项目是一个货币交易客户端,后端会走币安的开放接口,而币安的接口每分钟调用次数是有阈值的
目录
  • 背景
  • 节流是什么
  • 如何节流
    • 不使用节流
    • 使用节流之后
    • 模板
    • 示例
  • 结束语

    背景

    这个项目是一个货币交易客户端,后端会走币安的开放接口,而币安的接口每分钟调用次数是有阈值的,调多了直接接口返回错误。

    客户端里,有的窗口可能涉及 多个信息的查询 ,而这些信息需要调用不同的币安的接口,因此后端有的接口调用起来 权重很大(存在一个接口需要调用币安十几个接口的情况)。

    那么接口调用权重大的有两个窗口,其中一个是账户信息窗口。

    账户信息窗口需要实时的更新持仓盈亏以及强平价、开仓价等信息,这些信息分布在币安各个接口里,所以调用这个接口的 权重很大 。在这个窗口中我们添加了一个 强制刷新数据 按钮,用来 防止行情波动大 时卡住,影响 数据实时性

    那么当时的我还是欠考虑,忘记 给按钮添加防抖操作了,带来的结果就是在网络状况不好的情况下,有些比较急躁的用户会 连击 ,这样会一直调用接口,权重很快就达到阈值了。达到阈值后平仓平不了,亏钱甚至是爆仓,只能干瞪眼。

    所以我们要 控制用户连击行为 ,这就要用到节流了。

    另一个调用权重大的窗口是交易窗口,委托下单成功后会推送持仓数据、开仓价等。委托单有几个状态:挂单、部成(部分成交,多次)或者已成(完全成交,一次),部成状态和已成状态都会推送数据,有推送就要调接口。那么部成的情况下就很容易短时间内(0.5s)达到完全成交,也就是说有可能 一个委托单会触发好几次的接口调用 。这种客户端主要功能就是 下单 了,行情波动大的时候交易员都是快捷键操作,一秒几单,这是达到阈值的主要原因,不节流等着提桶吧。

    节流是什么

    介绍了这么多,有的小伙伴还不知道什么是“节流”,或者是听过 防抖节流 ,但是一直对这两个概念混淆,接下来我额外给大家做个小科普。

    想必很多人都有玩过 moba 游戏,我拿大众点的 英雄联盟王者荣耀 来举例。

    节流:英雄是会释放技能的,技能释放完会有冷却 cd,如果没有冷却完毕,不管你手按的再快,技能都放不出来。这个就是节流,一定时间疯狂连击我只触发一次。

    防抖:回城都知道吧,王者荣耀里回城所需的时间是 7 秒,如果在回城过程中你再次点击回城,那么回城时间是会被重置的。比如你点击回城过了 3 秒了,这个时间手欠又点了一下回城,好了,原本只要再等 3 秒就能泡泉水,这下你又要重新登 7 秒了。这个就是防抖。

    回归正题,因为我希望的是 允许用户刷新,但是不能太频繁,最好是一段时间内只允许刷新一次 ,是不是和上面防抖的例子一样,妥妥的防抖就安排上了嘛。

    如何节流

    不使用节流

    我们先使用一个简单的例子来讲。

    逻辑就是鼠标在灰色 box 上移动时,不断递增数字。

    <style>
        .box {
            background-color: grey;
            height: 100px;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 20px;
            color: #fff;
        }
    </style>
    <body>
        <div class="box" id="box">0</div>
        <script>
            const box = document.querySelector('#box');
            let count = 0;
            box.addEventListener('mousemove', ()=>{
                box.innerHTML = ++count;
            })
        </script>
    </body>
    

    可以看到,正常情况下 mousemove 事件会频繁触发。如果换成接口调用会咋样?想都不敢想。

    使用节流之后

    我们的需求还是鼠标移动时,数字递增,不同的是我们希望数字增长不要太快(事件触发频繁不要太快),这就要用到防抖了。

    我们来改造一下代码:

        const box = document.querySelector('#box');
        let count = 0;
        const throttle = (callback) => {
            let time = 0;
            return () => {
                const now = Date.now();
                const diff = (now - time) / 1000;
                if(diff > 0.5) {
                    callback();
                    time = now;
                }
            }
        }
        box.addEventListener('mousemove', throttle(()=>{
            box.innerHTML = ++count;
        }))
    

    其中,throttle 函数的返回值是一个函数,这个函数引用了外层变量 time,形成了一个闭包。

    变量 time 用来记录 上一次调用发生的时间 ,一开始默认为 0 ,这样下次触发就能 直接进行第一次调用

    后续触发事件回调时,判断当前触发回调的时间和上一次触发回调的 时间差 是不是 大于 我们规定的时间(0.5s),如果大于则允许调用,否则本着节流的逻辑,这次调用显然不被允许了。

    需要注意的是,在允许调用的情况下,我们要 更新 time 的值为 now

    我们来看看改造后的效果:

    模板

    相信大家都看出来了,朴素的节流有一套模板:

    const thrrotle = (callback) => {
        let time = 0;
        return () => {
            const now = Date.now();
            const diff = (now - time) / 1000;
            if(diff > 0.5) {
                callback();
                time = now;
            }
        }
    }
    

    还有种节流是通过一个 flag 变量控制是否允许调用回调的:

     function throttle(fn,delay) {
        let flag = true;
        return function() {
            if (flag) {
                setTimeout(() => {
                    fn.call(this); // 绑定 this
                    flag = true;
                }, delay);
            }
            flag = false;
        }
    }
    

    示例

    那么我项目中就是控制 10 秒内只允许触发一次接口调用,因此这里的 0.5 我要改成 10。

    // 点击刷新按钮尝试刷新
    const attempRefresh = (() => {
      let lastTime = new Date().getTime();
      const delay = 10;
      return () => {
        const now = new Date().getTime();
        const diff = (now - lastTime) / 1000;
        if (diff >= delay) {
          getAccountInfo(); // 调用接口
          lastTime = now;
        } else {
          message.info({
            content: `刷新过于频繁,请${delay - Math.floor(diff)}秒后尝试!`,
            key: EMessageKey.ACCOUNT_INFO,
          });
        }
      };
    })();
    

    经过这么一改造,用户第一次点击刷新的时候是允许刷新的,而在 10 秒内妄图再次刷新,展现给它的只有冰冷的提示语。

    结束语

    日常开发中,除了限制接口调用频率外,像页面 scroll 事件、窗口 resize 事件,为了性能考虑,都是需要进行节流处理的,而看完本文,相信大家都理解掌握了节流的方法,套用模板就完事了。但是还是希望大家能吃透,毕竟代码也不多,有了思路就不用去背代码了。学到就是赚到。

    以上就是JS按钮连击和接口调用频率限制防止客户爆仓的详细内容,更多关于JS限制按钮连击接口调用的资料请关注易盾网络其它相关文章!

    上一篇:Vue生命周期实例分析总结
    下一篇:没有了
    网友评论