认识防抖和节流函数
防抖debounce函数
案例
节流throttle函数
案例
生活中的例子
需求
Underscore库的介绍
防抖
index.html
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <input type="text" /> <button id="cancel">取消</button> <!-- <script src="01_debounce-this+args.js"></script> --> <!-- <script src="./02_debounce-立即执行.js"></script> --> <!-- <script src="./03_debounce-取消.js"></script> --> <!-- <script src="./04_debounce-函数返回值.js"></script> --> <script src="./05_debounce-异常捕获.js"></script> <script src="https://cdn.jsdelivr.net/npm/underscore@1.13.2/underscore-umd-min.js"></script> <script> const inputEl = document.querySelector("input"); let counter = 0; const inputChange = function (event) { console.log(`发送了第${counter++}次网络请求`, this, event); // throw new Error('error~') return "aaa"; }; // inputEl.oninput = inputChange // 防抖 // 1.第三方库underscore // inputEl.oninput = _.debounce(inputChange, 2000) // 2.自己封装 const debounceChange = debounce(inputChange, 2000, false, (res) => { console.log('函数返回值:', res); }); // inputEl.oninput = debounceChange; const tempCallback = (...args) => { debounceChange.apply(inputEl, args).then(res => { console.log('promise的返回值:', res); }).catch(err => console.log('捕获错误:', err)) } inputEl.onclick = tempCallback // 节流 // 1.第三方库underscore // inputEl.oninput = _.throttle(inputChange, 2000) // 取消功能 const cancelBtn = document.getElementById("cancel"); cancelBtn.onclick = function () { debounceChange.cancel(); }; </script> </body> </html>
this,args
-
function debounce(fn, delay) { // 1.定义定时器,保存上一次的定时器 let timer = null; // 2.真正执行的函数 const _debounce = function (...args) { // 3.取消上一次的定时器 if (timer) { clearTimeout(timer); } // 延迟执行 timer = setTimeout(() => { // 执行外部函数 fn.apply(this, args); }, delay); }; return _debounce; }
立即执行
-
function debounce(fn, delay, immediate = false) { // 1.定义定时器,保存上一次的定时器 let timer = null; // 判断之前是否执行过 let isInvoke = false // 2.真正执行的函数 const _debounce = function (...args) { // 3.取消上一次的定时器 if (timer) { clearTimeout(timer); } // 判断是否需要立即执行 if (immediate && !isInvoke) { // 立即执行 fn.apply(this, args); isInvoke = true } else { // 延迟执行 timer = setTimeout(() => { // 执行外部函数 fn.apply(this, args); // 执行完一次后,在下次执行前可以再次立即执行 isInvoke = false }, delay); } }; return _debounce; }
取消功能
-
function debounce(fn, delay, immediate = false) { // 1.定义定时器,保存上一次的定时器 let timer = null; // 判断之前是否执行过 let isInvoke = false // 2.真正执行的函数 const _debounce = function (...args) { // 3.取消上一次的定时器 if (timer) { clearTimeout(timer); } // 判断是否需要立即执行 if (immediate && !isInvoke) { // 立即执行 fn.apply(this, args); isInvoke = true } else { // 延迟执行 timer = setTimeout(() => { // 执行外部函数 fn.apply(this, args); // 执行完一次后,在下次执行前可以再次立即执行 isInvoke = false timer = null }, delay); } }; // 封装取消功能 _debounce.cancel = function () { if (timer) { clearTimeout(timer) timer = null isInvoke = false } } return _debounce; }
函数返回值
-
function debounce(fn, delay, immediate = false, resultCallback) { // 1.定义定时器,保存上一次的定时器 let timer = null; // 判断之前是否执行过 let isInvoke = false; // 2.真正执行的函数 const _debounce = function (...args) { return new Promise((resolve, reject) => { // 3.取消上一次的定时器 if (timer) { clearTimeout(timer); } // 判断是否需要立即执行 if (immediate && !isInvoke) { // 立即执行 const result = fn.apply(this, args); // 1.将函数返回值作为回调函数参数返回 if (resultCallback && typeof resultCallback === "function") { resultCallback(result); } // 2.将函数返回值通过resolve参数返回 resolve(result); isInvoke = true; } else { // 延迟执行 timer = setTimeout(() => { // 执行外部函数 const result = fn.apply(this, args); // 1.将函数返回值作为回调函数参数返回 if (resultCallback && typeof resultCallback === "function") { resultCallback(result); } // 2.将函数返回值通过resolve参数返回 resolve(result); // 执行完一次后,在下次执行前可以再次立即执行 isInvoke = false; timer = null; }, delay); } }); }; // 封装取消功能 _debounce.cancel = function () { if (timer) { clearTimeout(timer); timer = null; isInvoke = false; } }; return _debounce; }
异常捕获
-
function debounce(fn, delay, immediate = false, resultCallback) { // 1.定义定时器,保存上一次的定时器 let timer = null; // 判断之前是否执行过 let isInvoke = false; // 2.真正执行的函数 const _debounce = function (...args) { return new Promise((resolve, reject) => { // 3.取消上一次的定时器 if (timer) { clearTimeout(timer); } // 判断是否需要立即执行 if (immediate && !isInvoke) { try { // 立即执行 const result = fn.apply(this, args); // 1.将函数返回值作为回调函数参数返回 if (resultCallback && typeof resultCallback === 'function') { resultCallback(result); } // 2.将函数返回值通过resolve参数返回 resolve(result); } catch (err) { reject(err); } isInvoke = true; } else { // 延迟执行 timer = setTimeout(() => { try { // 执行外部函数 const result = fn.apply(this, args); // 1.将函数返回值作为回调函数参数返回 if (resultCallback && typeof resultCallback === 'function') { resultCallback(result); } // 2.将函数返回值通过resolve参数返回 resolve(result); } catch (err) { reject(err); } // 执行完一次后,在下次执行前可以再次立即执行 isInvoke = false; timer = null; }, delay); } }); }; // 封装取消功能 _debounce.cancel = function () { if (timer) { clearTimeout(timer); timer = null; isInvoke = false; } }; return _debounce; }
节流
index.html
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <input type="text" /> <button id="cancel">取消</button> <!-- <script src="01_throttle-基本实现.js"></script> --> <!-- <script src="02_throttle-leading.js"></script> --> <!-- <script src="03_throttle-trailing.js"></script> --> <!-- <script src="04_throttle-this+args.js"></script> --> <!-- <script src="05_throttle-cancel.js"></script> --> <!-- <script src="06_throttle-函数返回值.js"></script> --> <script src="07_throttle-异常捕获.js"></script> <script src="https://cdn.jsdelivr.net/npm/underscore@1.13.2/underscore-umd-min.js"></script> <script> const inputEl = document.querySelector("input"); let counter = 0; const inputChange = function (event) { console.log(`发送了第${counter++}次网络请求`, this, event); // throw new Error("error~"); return "aaa"; }; // inputEl.oninput = inputChange // 节流 // 1.第三方库underscore // inputEl.oninput = _.throttle(inputChange, 2000) // 2.自己封装 const _throttle = throttle(inputChange, 2000, { leading: false, trailing: true, resultCallback: function (res) { console.log("resultCallback:", res); }, }); // inputEl.oninput = _throttle; const tempCallback = (...args) => { _throttle.apply(inputEl, args) .then((res) => { console.log("promise的返回值:", res); }) .catch((err) => console.log(err)); }; inputEl.oninput = tempCallback; // 取消功能 const cancelBtn = document.querySelector("#cancel"); cancelBtn.onclick = function () { _throttle.cancel(); }; </script> </body> </html>
leading功能
-
function throttle(fn, interval, options = { leading: true, trailing: fasle }) { // 1.记录上一次开始时间 const { leading, trailing } = options; let lastTime = 0; // 2.事件触发时,真正执行的函数 const _throttle = function () { // 2.1.获取当前事件触发的时间 const nowTime = new Date().getTime(); if (!lastTime && !leading) { lastTime = nowTime } // 2.2.计算剩余多长时间去触发函数 const remainTime = interval - (nowTime - lastTime); if (remainTime <= 0) { // 2.3.真正执行函数 fn(); // 2.4.保留上次触发的时间 lastTime = nowTime; } }; return _throttle; }
trailing功能
-
function throttle(fn, interval, options = { leading: true, trailing: fasle }) { // 1.记录上一次开始时间 const { leading, trailing } = options; let lastTime = 0; let timer = null // 2.事件触发时,真正执行的函数 const _throttle = function () { // 2.1.获取当前事件触发的时间 const nowTime = new Date().getTime(); if (!lastTime && !leading) { lastTime = nowTime } // 2.2.计算剩余多长时间去触发函数 const remainTime = interval - (nowTime - lastTime); if (remainTime <= 0) { if (timer) { clearTimeout(timer) timer = null } // 2.3.真正执行函数 fn(); // 2.4.保留上次触发的时间 lastTime = nowTime; return } if (trailing && !timer) { timer = setTimeout(() => { timer = null lastTime = !trailing ? 0 : new Date().getTime() fn() }, remainTime); } }; return _throttle; }
this,args
-
function throttle(fn, interval, options = { leading: true, trailing: fasle }) { // 1.记录上一次开始时间 const { leading, trailing } = options; let lastTime = 0; let timer = null // 2.事件触发时,真正执行的函数 const _throttle = function (...args) { // 2.1.获取当前事件触发的时间 const nowTime = new Date().getTime(); if (!lastTime && !leading) { lastTime = nowTime } // 2.2.计算剩余多长时间去触发函数 const remainTime = interval - (nowTime - lastTime); if (remainTime <= 0) { if (timer) { clearTimeout(timer) timer = null } // 2.3.真正执行函数 fn.apply(this, args); // 2.4.保留上次触发的时间 lastTime = nowTime; return } if (trailing && !timer) { timer = setTimeout(() => { timer = null lastTime = !trailing ? 0 : new Date().getTime() fn.apply(this, args) }, remainTime); } }; return _throttle; }
取消功能
-
function throttle(fn, interval, options = { leading: true, trailing: fasle }) { // 1.记录上一次开始时间 const { leading, trailing } = options; let lastTime = 0; let timer = null // 2.事件触发时,真正执行的函数 const _throttle = function (...args) { // 2.1.获取当前事件触发的时间 const nowTime = new Date().getTime(); if (!lastTime && !leading) { lastTime = nowTime } // 2.2.计算剩余多长时间去触发函数 const remainTime = interval - (nowTime - lastTime); if (remainTime <= 0) { if (timer) { clearTimeout(timer) timer = null } // 2.3.真正执行函数 fn.apply(this, args); // 2.4.保留上次触发的时间 lastTime = nowTime; return } if (trailing && !timer) { timer = setTimeout(() => { timer = null lastTime = !trailing ? 0 : new Date().getTime() fn.apply(this, args) }, remainTime); } }; _throttle.cancel = function() { if (timer) { clearTimeout(timer) } timer = null lastTime = 0 } return _throttle; }
函数返回值
-
function throttle(fn, interval, options = { leading: true, trailing: fasle }) { // 1.记录上一次开始时间 const { leading, trailing, resultCallback } = options; let lastTime = 0; let timer = null; // 2.事件触发时,真正执行的函数 const _throttle = function (...args) { return new Promise((resolve, rejecte) => { // 2.1.获取当前事件触发的时间 const nowTime = new Date().getTime(); if (!lastTime && !leading) { lastTime = nowTime; } // 2.2.计算剩余多长时间去触发函数 const remainTime = interval - (nowTime - lastTime); if (remainTime <= 0) { if (timer) { clearTimeout(timer); timer = null; } // 2.3.真正执行函数 const result = fn.apply(this, args); if (resultCallback) { resultCallback(result); } resolve(result); // 2.4.保留上次触发的时间 lastTime = nowTime; return; } if (trailing && !timer) { timer = setTimeout(() => { timer = null; lastTime = !trailing ? 0 : new Date().getTime(); const result = fn.apply(this, args); if (resultCallback) { resultCallback(result); } resolve(result); }, remainTime); } }); }; _throttle.cancel = function () { if (timer) { clearTimeout(timer); } timer = null; lastTime = 0; }; return _throttle; }
异常捕获
-
function throttle(fn, interval, options = { leading: true, trailing: fasle }) { // 1.记录上一次开始时间 const { leading, trailing, resultCallback } = options; let lastTime = 0; let timer = null; // 2.事件触发时,真正执行的函数 const _throttle = function (...args) { return new Promise((resolve, rejecte) => { // 2.1.获取当前事件触发的时间 const nowTime = new Date().getTime(); if (!lastTime && !leading) { lastTime = nowTime; } // 2.2.计算剩余多长时间去触发函数 const remainTime = interval - (nowTime - lastTime); if (remainTime <= 0) { if (timer) { clearTimeout(timer); timer = null; } try { // 2.3.真正执行函数 const result = fn.apply(this, args); if (resultCallback) { resultCallback(result); } resolve(result); } catch (err) { rejecte(err); } // 2.4.保留上次触发的时间 lastTime = nowTime; return; } if (trailing && !timer) { timer = setTimeout(() => { timer = null; lastTime = !trailing ? 0 : new Date().getTime(); try { const result = fn.apply(this, args); if (resultCallback) { resultCallback(result); } resolve(result); } catch (err) { rejecte(err); } }, remainTime); } }); }; _throttle.cancel = function () { if (timer) { clearTimeout(timer); } timer = null; lastTime = 0; }; return _throttle; }