JS按鈕連擊和接口調(diào)用頻率限制防止客戶爆倉(cāng)
背景
這個(gè)項(xiàng)目是一個(gè)貨幣交易客戶端,后端會(huì)走幣安的開放接口,而幣安的接口每分鐘調(diào)用次數(shù)是有閾值的,調(diào)多了直接接口返回錯(cuò)誤。
客戶端里,有的窗口可能涉及 多個(gè)信息的查詢 ,而這些信息需要調(diào)用不同的幣安的接口,因此后端有的接口調(diào)用起來 權(quán)重很大(存在一個(gè)接口需要調(diào)用幣安十幾個(gè)接口的情況)。
那么接口調(diào)用權(quán)重大的有兩個(gè)窗口,其中一個(gè)是賬戶信息窗口。
賬戶信息窗口需要實(shí)時(shí)的更新持倉(cāng)盈虧以及強(qiáng)平價(jià)、開倉(cāng)價(jià)等信息,這些信息分布在幣安各個(gè)接口里,所以調(diào)用這個(gè)接口的 權(quán)重很大 。在這個(gè)窗口中我們添加了一個(gè) 強(qiáng)制刷新數(shù)據(jù) 按鈕,用來 防止行情波動(dòng)大 時(shí)卡住,影響 數(shù)據(jù)實(shí)時(shí)性。
那么當(dāng)時(shí)的我還是欠考慮,忘記 給按鈕添加防抖操作了,帶來的結(jié)果就是在網(wǎng)絡(luò)狀況不好的情況下,有些比較急躁的用戶會(huì) 連擊 ,這樣會(huì)一直調(diào)用接口,權(quán)重很快就達(dá)到閾值了。達(dá)到閾值后平倉(cāng)平不了,虧錢甚至是爆倉(cāng),只能干瞪眼。
所以我們要 控制用戶連擊行為 ,這就要用到節(jié)流了。
另一個(gè)調(diào)用權(quán)重大的窗口是交易窗口,委托下單成功后會(huì)推送持倉(cāng)數(shù)據(jù)、開倉(cāng)價(jià)等。委托單有幾個(gè)狀態(tài):掛單、部成(部分成交,多次)或者已成(完全成交,一次),部成狀態(tài)和已成狀態(tài)都會(huì)推送數(shù)據(jù),有推送就要調(diào)接口。那么部成的情況下就很容易短時(shí)間內(nèi)(0.5s)達(dá)到完全成交,也就是說有可能 一個(gè)委托單會(huì)觸發(fā)好幾次的接口調(diào)用 。這種客戶端主要功能就是 下單 了,行情波動(dòng)大的時(shí)候交易員都是快捷鍵操作,一秒幾單,這是達(dá)到閾值的主要原因,不節(jié)流等著提桶吧。
節(jié)流是什么
介紹了這么多,有的小伙伴還不知道什么是“節(jié)流”,或者是聽過 防抖 和 節(jié)流 ,但是一直對(duì)這兩個(gè)概念混淆,接下來我額外給大家做個(gè)小科普。
想必很多人都有玩過 moba 游戲,我拿大眾點(diǎn)的 英雄聯(lián)盟 和 王者榮耀 來舉例。
節(jié)流:英雄是會(huì)釋放技能的,技能釋放完會(huì)有冷卻 cd,如果沒有冷卻完畢,不管你手按的再快,技能都放不出來。這個(gè)就是節(jié)流,一定時(shí)間瘋狂連擊我只觸發(fā)一次。
防抖:回城都知道吧,王者榮耀里回城所需的時(shí)間是 7 秒,如果在回城過程中你再次點(diǎn)擊回城,那么回城時(shí)間是會(huì)被重置的。比如你點(diǎn)擊回城過了 3 秒了,這個(gè)時(shí)間手欠又點(diǎn)了一下回城,好了,原本只要再等 3 秒就能泡泉水,這下你又要重新登 7 秒了。這個(gè)就是防抖。
回歸正題,因?yàn)槲蚁M氖?允許用戶刷新,但是不能太頻繁,最好是一段時(shí)間內(nèi)只允許刷新一次 ,是不是和上面防抖的例子一樣,妥妥的防抖就安排上了嘛。
如何節(jié)流
不使用節(jié)流
我們先使用一個(gè)簡(jiǎn)單的例子來講。
邏輯就是鼠標(biāo)在灰色 box 上移動(dòng)時(shí),不斷遞增數(shù)字。
<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 事件會(huì)頻繁觸發(fā)。如果換成接口調(diào)用會(huì)咋樣?想都不敢想。
使用節(jié)流之后
我們的需求還是鼠標(biāo)移動(dòng)時(shí),數(shù)字遞增,不同的是我們希望數(shù)字增長(zhǎng)不要太快(事件觸發(fā)頻繁不要太快),這就要用到防抖了。
我們來改造一下代碼:
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 函數(shù)的返回值是一個(gè)函數(shù),這個(gè)函數(shù)引用了外層變量 time,形成了一個(gè)閉包。
變量 time 用來記錄 上一次調(diào)用發(fā)生的時(shí)間 ,一開始默認(rèn)為 0 ,這樣下次觸發(fā)就能 直接進(jìn)行第一次調(diào)用 。
后續(xù)觸發(fā)事件回調(diào)時(shí),判斷當(dāng)前觸發(fā)回調(diào)的時(shí)間和上一次觸發(fā)回調(diào)的 時(shí)間差 是不是 大于 我們規(guī)定的時(shí)間(0.5s),如果大于則允許調(diào)用,否則本著節(jié)流的邏輯,這次調(diào)用顯然不被允許了。
需要注意的是,在允許調(diào)用的情況下,我們要 更新 time 的值為 now。
我們來看看改造后的效果:

模板
相信大家都看出來了,樸素的節(jié)流有一套模板:
const thrrotle = (callback) => {
let time = 0;
return () => {
const now = Date.now();
const diff = (now - time) / 1000;
if(diff > 0.5) {
callback();
time = now;
}
}
}
還有種節(jié)流是通過一個(gè) flag 變量控制是否允許調(diào)用回調(diào)的:
function throttle(fn,delay) {
let flag = true;
return function() {
if (flag) {
setTimeout(() => {
fn.call(this); // 綁定 this
flag = true;
}, delay);
}
flag = false;
}
}
示例
那么我項(xiàng)目中就是控制 10 秒內(nèi)只允許觸發(fā)一次接口調(diào)用,因此這里的 0.5 我要改成 10。
// 點(diǎn)擊刷新按鈕嘗試刷新
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(); // 調(diào)用接口
lastTime = now;
} else {
message.info({
content: `刷新過于頻繁,請(qǐng)${delay - Math.floor(diff)}秒后嘗試!`,
key: EMessageKey.ACCOUNT_INFO,
});
}
};
})();
經(jīng)過這么一改造,用戶第一次點(diǎn)擊刷新的時(shí)候是允許刷新的,而在 10 秒內(nèi)妄圖再次刷新,展現(xiàn)給它的只有冰冷的提示語。
結(jié)束語
日常開發(fā)中,除了限制接口調(diào)用頻率外,像頁面 scroll 事件、窗口 resize 事件,為了性能考慮,都是需要進(jìn)行節(jié)流處理的,而看完本文,相信大家都理解掌握了節(jié)流的方法,套用模板就完事了。但是還是希望大家能吃透,畢竟代碼也不多,有了思路就不用去背代碼了。學(xué)到就是賺到。
以上就是JS按鈕連擊和接口調(diào)用頻率限制防止客戶爆倉(cāng)的詳細(xì)內(nèi)容,更多關(guān)于JS限制按鈕連擊接口調(diào)用的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript中document.activeELement焦點(diǎn)元素介紹
這篇文章主要給大家分享 JavaScript中document.activeELement焦點(diǎn)元素介紹,下面文章圍繞了document.activeElement屬性展開詳細(xì)內(nèi)容,需要的朋友可以參考一下,希望對(duì)大家有所幫助2021-11-11
smartbanner.js實(shí)現(xiàn)可定制智能應(yīng)用橫幅使用示例
這篇文章主要為大家介紹了smartbanner.js實(shí)現(xiàn)可定制智能應(yīng)用橫幅使用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
微信公眾號(hào) 提示:Unauthorized API function 問題解決方法
這篇文章主要介紹了微信公眾號(hào) 提示:Unauthorized API function 問題解決方法的相關(guān)資料,這里提供了出現(xiàn)提示的解決方法,需要的朋友可以參考下2016-12-12

