一、節流函式
1. 使用場景
DOM.onclick()
事件,我們給一個DOM節點繫結了點選事件,當點選該元素時觸發事件函式的執行,但是當我們頻繁點選該元素時,就會不斷觸發該點選事件,如果該點選事件觸發的事件函式是DOM元素的,就會造成很高的效能消耗,可能會造成頁面的卡頓。
所以此時我們應該限制該事件的觸發頻率,減少頁面的開銷。
2. 原理
連續觸發事件,但是事件函式只在在規定的週期之內只執行一次。
3. 程式碼實現
function throttle(fn, wait = 500) {
let lastTime = 0 // 初始化上一次呼叫的事件
return function () {
let args = [].slice.call(arguments) // 將類陣列轉化為陣列
let nowTime = new Date().getTime() // 獲取當前時間
if(nowTime - lastTime > wait) {
fn.apply(this, args)
lastTime = nowTime // 把上一次呼叫時間重新賦值
}
}
}
// 使用
let btn = document.getElementById('btn')
let fn = function () {
console.log(1)
}
btn.onclick = throttle(fn, 1000)
複製程式碼
在給按鈕加上點選事件後,即使一直不停的點選按鈕,也只會每隔1000ms
執行一次事件處理函式。
二、防抖函式
1.使用場景
例如我們在百度搜尋的輸入框輸入我們想要搜尋的內容,在我們停止輸入後一小段時間(delay
)後就會得你輸入框得內容然後進行搜尋,如果你在輸入後暫停的時間小於規定的時間(delay
),就會重新計算該時間。
2.原理
所謂防抖,就是指觸發事件後在 n 秒內函式只能執行一次,如果在 n 秒內又觸發了事件,則會重新計算函式執行時間。
3. 程式碼實現
function debounce(fn, delay) {
let timer = null
return function () {
let _self = this
let args = [].slice.call(arguments)
clearTimout(timer)
timer = setTimout(function () {
fn.apply(_self, args)
}, delay)
}
}
// 使用
let inp = document.getElementById('inp')
function handler() {
console.log(this.value)
}
inp.oninput = debounce(handler, 500)
複製程式碼
在使用節流函式後,我們在暫停輸入的500ms
後就會輸入輸入框內的值,暫停時間小於500ms
,則不會輸出,將重新計算函式執行時間。
三、分時函式
比如我們在將一個很大的資料渲染成列表的時候,我們要求必須將所有資料渲染完成,不能使用懶載入,所以這樣當我們在短時間內往頁面新增大量的DOM
節點的時候,顯然會造成瀏覽器的卡頓。
let arr = []
for(let a = 0; a < 1000; a++) {
arr.push(a)
}
function render(data) {
for(let i = 0; i < arr.length; i++) {
let div = document.createElement('div')
div.innerHTML = arr[i]
document.body.appenChild(div)
}
}
render(arr)
複製程式碼
所以我們我們建立一個函式,然節點的新增分時進行,比如把在1s
新增1000個節點改為每隔200ms
新增20個節點。
let timeChunk = function (data, fn, count = 20, delay = 200) {
let obj,timer
let start = function () {
for(let i = 0; i < Math.min(count, data.length); i++) {
let obj = data.shift()
fn(obj)
}
}
return function () {
timer = setInterval(function () {
if(data.length === 0) {
return clearInterval(timer)
}
start()
}, delay)
}
}
複製程式碼
使用分時函式
let arr = []
for (let a = 0; a < 1000; a++) {
arr.push(a)
}
function render(data) {
let div = document.createElement('div')
div.innerText = data
document.body.appendChild(div)
}
let renderlist = timeChunk(arr, render, 20, 200)
renderlist()
複製程式碼
這樣在呼叫分時函式後每隔200ms
建立20個節點。
四、惰性函式
在前端開發中,因為瀏覽器的差異,一些嗅探工作是不可避免的,比如要實現一個在各個瀏覽器中都通用的新增事件函式。常見寫法:
let addEvent = function (element, type, handler) {
if(window.addEventListener) {
return element.addEventLisenter(type, handler, false)
} else if (window.attachEvent) {
return element.attachEvent('on'+type, handler)
}
}
複製程式碼
但是我們每次執行函式的時候都要進行分支判斷,然後當我們在確定了在哪一種瀏覽器中執行該函式的時候,我們只需要在第一次判斷,後面的使用都不用判斷,因為我們是在同一個瀏覽器執行該函式。
所以我們可以使用惰性載入函式,在函式體內往往都會有一些分支判斷,但是在第一次進入分支條件後,在函式內部會重寫這個函式,重寫之後就是我們所期望的函式,在下一次再進入函式的時候不用在進行分支判斷。
let addEvent = function (element, type, handler) {
if(window.addEventListener) {
addEvemt = function(element, type, handler) {
element.addEventLisenter(type, handler, false)
}
} else if (window.attachEvent) {
addEvent = function(element, type, handler) {
element.attachEvent('on'+type, handler)
}
}
addEvent(element, type, handler)
}
複製程式碼