在前端开发的过程中,我们经常会需要绑定一些持续触发的事件,如 resize、scroll、mousemove 等等,但有些时候我们并不希望在事件持续触发的过程中那么频繁地去执行函数。
防抖(debounce):所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
节流(throttle):所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
防抖是将多次执行变为最后一次执行,节流是将多次执行变为每隔一段时间执行。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>未做防抖节流</title> </head> <body> <div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div> <script> let num = 1; let content = document.getElementById(‘content‘); function count() { console.log(num); content.innerHTML = num++; }; content.onmousemove = count; </script> </body> </html>
当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定时间到来之前,又触发了事件,就重新开始延时。也就是说当一个用户一直触发这个函数,且每次触发函数的间隔小于既定时间,那么防抖的情况下只会执行一次。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>先防抖再执行</title> </head> <body> <div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div> <script> let num = 1; let content = document.getElementById(‘content‘); function count() { console.log(num); content.innerHTML = num++; }; function debounce(func, wait) { let timeout; return function() { let context = this; let args = arguments; if (timeout) clearTimeout(timeout); timeout = setTimeout(() => { func.apply(context, args) }, wait); } } content.onmousemove = debounce(count, 1000); </script> </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>先执行再防抖</title> </head> <body> <div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div> <script> let num = 1; let content = document.getElementById(‘content‘); function count() { console.log(num); content.innerHTML = num++; }; function debounce(func, wait) { let timeout; return function() { let context = this; let args = arguments; if (timeout) clearTimeout(timeout); let callNow = !timeout; timeout = setTimeout(() => { timeout = null; }, wait) if (callNow) func.apply(context, args) } } content.onmousemove = debounce(count, 1000); </script> </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>防抖结合</title> </head> <body> <div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div> <script> let num = 1; let content = document.getElementById(‘content‘); function count() { console.log(num); content.innerHTML = num++; }; /** * @desc 函数防抖 * @param func 函数 * @param wait 延迟执行毫秒数 * @param immediate true 表立即执行,false 表非立即执行 */ function debounce(func, wait, immediate) { let timeout; return function() { let context = this; let args = arguments; if (timeout) clearTimeout(timeout); if (immediate) { var callNow = !timeout; timeout = setTimeout(() => { timeout = null; }, wait) if (callNow) func.apply(context, args) } else { timeout = setTimeout(function() { func.apply(context, args) }, wait); } } } content.onmousemove = debounce(count, 1000, false); </script> </body> </html>
当持续触发事件时,保证在一定时间内只调用一次事件处理函数,意思就是说,假设一个用户一直触发这个函数,且每次触发小于既定值,函数节流会每隔这个时间调用一次。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>节流时间戳版</title> </head> <body> <div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div> <script> let num = 1; let content = document.getElementById(‘content‘); function count() { console.log(num); content.innerHTML = num++; }; function throttle(func, wait) { let previous = 0; return function() { let now = Date.now(); let context = this; let args = arguments; if (now - previous > wait) { func.apply(context, args); previous = now; } } } content.onmousemove = throttle(count, 1000); </script> </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>节流定时器版</title> </head> <body> <div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div> <script> let num = 1; let content = document.getElementById(‘content‘); function count() { console.log(num); content.innerHTML = num++; }; function throttle(func, wait) { let timeout; return function() { let context = this; let args = arguments; if (!timeout) { timeout = setTimeout(() => { timeout = null; func.apply(context, args) }, wait) } } } content.onmousemove = throttle(count, 1000); </script> </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>节流结合版</title> </head> <body> <div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div> <script> let num = 1; let content = document.getElementById(‘content‘); function count() { console.log(num); content.innerHTML = num++; }; /** * @desc 函数节流 * @param func 函数 * @param wait 延迟执行毫秒数 * @param type 1 表时间戳版,2 表定时器版 */ function throttle(func, wait, type) { if (type === 1) { console.log("1:"); var previous = 0; } else if (type === 2) { console.log("2:"); var timeout; } return function() { let context = this; let args = arguments; if (type === 1) { let now = Date.now(); if (now - previous > wait) { func.apply(context, args); previous = now; } } else if (type === 2) { if (!timeout) { timeout = setTimeout(() => { timeout = null; func.apply(context, args) }, wait) } } } } content.onmousemove = throttle(count, 1000, 2); </script> </body> </html>
防抖是控制次数,节流是控制频率。
防抖是将多次执行变为最后一次执行,节流是将多次执行变为每隔一段时间执行。
https://www.jianshu.com/p/c8b86b09daf0
原文:https://www.cnblogs.com/antao/p/13248359.html