<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
.btn-loading-circle:after {
content: "\27F3";
display: inline-block;
animation: mrotate 1.6s linear infinite 0s;
pointer-events: none;
}
@keyframes mrotate {
100% {
transform: rotate(1turn);
}
}
.disabled-font-color-gray {
color: #cecece !important;
pointer-events: none;
}
</style>
</head>
<body>
<h1>去抖:异步,立即,延迟</h1>
<h2>去抖:1.异步执行(触发请求的点击)</h2>
<h3>单个异步操作</h3>
<button id="btnSingle">无状态变化</button>
<button id="btnSingleLoading">带加载中状态</button>
<h3>多个异步操作</h3>
<button id="btnMultiple">无状态变化(如验证码倒计时)</button>
<button id="btnMultipleLoading">带加载中状态(如验证码倒计时)</button>
<h2>去抖:2.立即执行(触发动画或大量计算的操作,如转盘的点击旋转按钮)</h2>
<button id="btnDebounceImmediate">去抖:2.立即执行</button>
<a href="'http://demowap.lihaipeng.net/rotary/arr">线上示例</a>
<h2>去抖:2.1 立即执行+异步(触发请求的点击,兼容返回时间超过间隔时间)</h2>
<button id="btnDebounceImmediateAsync">去抖:2.1 立即执行+异步</button>
<button id="btnDebounceImmediateAsyncDelay">
去抖:2.1 立即执行+异步,超过间隔时间
</button>
<h2>去抖:3.延迟执行(模糊搜索)</h2>
<input id="inputDebounce" />
<a href="'http://demoweb.lihaipeng.net/rotary/">线上示例</a>
<h1>节流:onresize&onscroll</h1>
<script>
const btnSingle = document.getElementById("btnSingle");
btnSingle.onclick = debounceAsync(async () => {
console.log("btnSingle");
await requestApiMock();
});
const btnSingleLoading = document.getElementById("btnSingleLoading");
btnSingleLoading.onclick = debounceAsync(async (e) => {
console.log("btnSingleLoading");
const self = e.target;
self.classList.add("btn-loading-circle");
await requestApiMock();
self.classList.remove("btn-loading-circle");
});
const btnMultiple = document.getElementById("btnMultiple");
btnMultiple.onclick = debounceAsync(async (e) => {
console.log("btnMultiple");
const self = e.target;
await requestApiMock();
await countdownSeconds((seconds) => {
self.innerHTML = seconds === 0 ? "重新发送" : seconds + "s";
}, 3);
});
const btnMultipleLoading = document.getElementById("btnMultipleLoading");
btnMultipleLoading.onclick = debounceAsync(async (e) => {
console.log("btnMultipleLoading");
const self = e.target;
self.classList.add("btn-loading-circle");
const data = await requestApiMock({ success: true });
self.classList.remove("btn-loading-circle");
if (data.success === true) {
self.classList.add("disabled-font-color-gray");
await countdownSeconds((seconds) => {
self.innerHTML = seconds === 0 ? "重新发送" : seconds + "s";
}, 3);
self.classList.remove("disabled-font-color-gray");
}
});
function debounceAsync(func) {
let isDisable = false;
return async function () {
if (isDisable === true) return;
isDisable = true;
await func.apply(this, arguments);
isDisable = false;
};
}
function countdownSeconds(setSeconds, totalSecond = 60) {
return new Promise((resolve) => {
let seconds = totalSecond;
setSeconds(seconds);
seconds--;
const timer = setInterval(() => {
setSeconds(seconds);
if (seconds === 0) {
clearInterval(timer);
resolve();
} else {
seconds--;
}
}, 1000);
});
}
const btnDebounceImmediate = document.getElementById(
"btnDebounceImmediate"
);
btnDebounceImmediate.onclick = debounceImmediate(() => {
console.log("debounceImmediate");
});
function debounceImmediate(func, wait = 2000) {
let previous = 0;
return function () {
const now = +new Date();
const remaining = previous + wait - now;
if (previous === 0 || remaining <= 0) {
previous = now;
func.apply(this, arguments);
}
};
}
const btnDebounceImmediateAsync = document.getElementById(
"btnDebounceImmediateAsync"
);
const btnDebounceImmediateAsyncDelay = document.getElementById(
"btnDebounceImmediateAsyncDelay"
);
btnDebounceImmediateAsync.onclick = debounceImmediateAsync(async (e) => {
console.log("btnDebounceImmediateAsync");
const self = e.target;
self.classList.add("btn-loading-circle");
await requestApiMock();
self.classList.remove("btn-loading-circle");
});
btnDebounceImmediateAsyncDelay.onclick = debounceImmediateAsync(async (e) => {
console.log("btnDebounceImmediateAsyncDelay");
const self = e.target;
self.classList.add("btn-loading-circle");
await requestApiMock({},4000);
self.classList.remove("btn-loading-circle");
});
function debounceImmediateAsync(func, wait = 2000) {
let previous = 0;
let isDisable = false;
return async function () {
if (isDisable === true) return;
const now = +new Date();
const remaining = previous + wait - now;
if (previous === 0 || remaining <= 0) {
isDisable = true;
await func.apply(this, arguments);
isDisable = false;
previous = now;
}
};
}
const inputDebounce = document.getElementById("inputDebounce");
inputDebounce.oninput = debounce(async (e) => {
const self = e.target;
console.log("inputDebounce", self.value);
await requestApiMock();
});
function debounce(func, wait = 1500) {
let timer = null;
return function () {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, arguments);
timer = null;
}, wait);
};
}
window.onresize = throttle(() => console.log("throttle onresize"), 2000);
window.onscroll = throttle(() => console.log("throttle onscroll"), 2000);
function throttle(func, wait = 1000) {
let previous = 0;
let timer = null;
return function () {
const now = +new Date();
const remaining = previous + wait - now;
if (previous === 0 || remaining <= 0) {
previous = now;
func.apply(this, arguments);
} else if (!timer) {
timer = setTimeout(() => {
clearTimeout(timer);
timer = null;
func.apply(this, arguments);
}, remaining);
}
};
}
async function requestApiMock(data = {}, delay = 1500) {
return new Promise(async (resolve) => {
console.log("requestApiMock start");
setTimeout(() => {
resolve(data);
console.log("requestApiMock end");
}, delay);
return;
const response = await getWalletInfo();
console.log("response---:", response);
resolve(response);
});
}
</script>
</body>
</html>