一、防抖函數手動寫
防抖函數定義:一個需要頻繁觸發的函數,在規定時間內只讓最后一次生效,前面的不生效
/** * @param {*} fn 包裝的事件回調函數 * @param {*} delay 等待時間 */ export function debounce(fn, delay) { // 記錄上一次的延時器 var timer = null // 將debounce處理結果當作函數返回 return () => { // 保留調用時的this上下文 let context = this // 保留調用時傳入的參數 let args = arguments // 每次事件被觸發時,都去清除之前的舊定時器 if (timer) { clearTimeout(timer) } // 重新設置新的延時器 timer = setTimeout(() => { // 解決this指向問題 fn.apply(context, args) }, delay) } } // 用debounce來包裝scroll的回調 const better_scroll = debounce(() => console.log('觸發了滾動事件'), 1000)
注意:debounce 的問題在於它“太有耐心了”。試想,如果用戶的操作十分頻繁——他每次都不等 debounce 設置的 delay 時間結束就進行下一次操作,於是每次 debounce 都為該用戶重新生成定時器,回調函數被延遲了不計其數次。頻繁的延遲會導致用戶遲遲得不到響應,用戶同樣會產生“這個頁面卡死了”的觀感
用 Throttle 來優化 Debounce
// fn是我們需要包裝的事件回調, delay是時間間隔的閾值 function throttle(fn, delay) { // last為上一次觸發回調的時間, timer是定時器 let last = 0, timer = null // 將throttle處理結果當作函數返回 return function () { // 保留調用時的this上下文 let context = this // 保留調用時傳入的參數 let args = arguments // 記錄本次觸發回調的時間 let now = +new Date() // 判斷上次觸發的時間和本次觸發的時間差是否小於時間間隔的閾值 if (now - last < delay) { // 如果時間間隔小於我們設定的時間間隔閾值,則為本次觸發操作設立一個新的定時器 clearTimeout(timer) timer = setTimeout(function () { last = now fn.apply(context, args) }, delay) } else { // 如果時間間隔超出了我們設定的時間間隔閾值,那就不等了,無論如何要反饋給用戶一次響應 last = now fn.apply(context, args) } } } // 用新的throttle包裝scroll的回調 const better_scroll = throttle(() => console.log('觸發了滾動事件'), 1000) document.addEventListener('scroll', better_scroll)
二、在 Vue 里使用 lodash 中的 Debouncing 和 Throttling
安裝
可以通過 yarn 或 npm 安裝 lodash。
# Yarn
$ yarn add lodash
# NPM
$ npm install lodash --save
注意:如果我們不想導入lodash
的所有內容,而只導入所需的部分,則可以通過一些Webpack構建自定義來解決問題。 還可以使用lodash.throttle
和lodash.debounce
等軟件包分別安裝和導入lodash
的各個部分。
throttling 方法
要對事件進行節流處理方法非常簡單,只需將要調用的函數包裝在lodash的_.throttle
函數中即可。
<template> <button @click="throttledMethod()">Click me as fast as you can!</button> </template> <script> import _ from 'lodash' export default { methods: { throttledMethod: _.throttle(() => { console.log('I get fired every two seconds!') }, 2000) } } </script>
debouncing 方法
盡管節流在某些情況下很有用,但一般情況我們經常使用的是防抖。 防抖實質上將我們的事件分組在一起,並防止它們被頻繁觸發。 要在Vue組件中使用節流,只需將要調用的函數包裝在lodash的_.debounce
函數中。
<template> <button @click="throttledMethod()">Click me as fast as you can!</button> </template> <script> import _ from 'lodash' export default { methods: { throttledMethod: _.debounce(() => { console.log('I only get fired once every two seconds, max!') }, 2000) } } </script>