原由:
自己剛在研究js的防抖引發的一個問題(因為不在本篇范圍不說了奧),代碼:
var count = 1; var container = document.getElementById('container'); function getUserAction() { container.innerHTML = count++; }; function debounce(f, t) { let tid; return function() {
if(tid) {
clearTimeout(tid);
} tid = setTimeout(f, t); } } container.onmousemove = debounce(getUserAction, 3000);
如上所示,基本防抖都有了,但是我想指定getUserAction中的this給debounce,我這個時候就腦缺了...
var count = 1; var container = document.getElementById('container'); function getUserAction() { // this 指向 window
container.innerHTML = count++; }; function debounce(f, t) { let tid; return () => { // this肯定指向 document.getElementById('container')的html元素
if(tid) {
clearTimeout(tid);
}
tid = setTimeout(f.call(this), t);
}
}
container.onmousemove = debounce(getUserAction, 3000);
自己去運行下啊,這時候發現當鼠標移動在container范圍中,會失去防抖的功能,也就是說,setTimeOut根本沒有執行!!!!(自認為)
其實眼見的同學已經發現了,f.call(this)其實已經執行了該函數,而不是函數聲明或者code
根據MDN的解釋:
var timerId = setTimeout(func|code, delay)
functionfunction
是你想要在到期時間(delay
毫秒)之后執行的函數。
code這是一個可選語法,你可以使用字符串而不是function
,在delay
毫秒之后編譯和執行字符串 (使用該語法是不推薦的, 原因和使用 eval()
一樣,有安全風險)。
delay 可選延遲的毫秒數 (一秒等於1000毫秒),函數的調用會在該延遲之后發生。如果省略該參數,delay取默認值0,意味着“馬上”執行,或者盡快執行。不管是哪種情況,實際的延遲時間可能會比期待的(delay毫秒數) 值長,原因請查看Reasons for delays longer than specified。
所以,答案很明顯了!!!代碼改下啊:
var count = 1; var container = document.getElementById('container'); function getUserAction() { // this 指向 window container.innerHTML = count++; }; function debounce(f, t) { let tid; return () => { // this肯定指向 document.getElementById('container')的html元素
if(tid) {
clearTimeout(tid);
}
tid = setTimeout(() => { // 更改為function就行了
f.call(this)
}, t);
}
}
container.onmousemove = debounce(getUserAction, 3000);
那么這個問題解決了啊.好了本文到此結束!!!!
開....開玩笑的奧,是這樣的,這時候的確是解決問題了,但我自己想了下,那 tid = setTimeout(f.call(this), t); 到底有沒有執行!!!!!
經過,我多方的考證以及最近看了<<你不知道的js>>中了解到,其實在js中存在一個內部的任務隊列,用於存儲異步任務(setTimeOut,點擊事件的回調函數等)
舉個栗子:
setTimeout(() => { console.log(1); },0) console.log(2); // result : 2 1
其實,通俗來說同步的任務會按照代碼順序來執行函數,而異步的(當前就是setTimeOut會加入任務隊列,即使它的delay為0)
那我們再來個demo,體現有序的隊列:
setTimeout(() => { console.log(1); }, 200) setTimeout(() => { console.log(2); }, 100) console.log(3); setTimeout(() => { console.log(4); }, 0) // 根據delay的長短來順序加入任務隊列 console.log(5); // 3 5 4 2 1
說這么多,我就想說明.既然你聲明了定時器,那肯定會加入任務隊列去執行的.那問題來了,那我的f.call(this)去哪了?眾所周知,js中若function沒有指定return,默認是返回undefined的,那是不是代表.我的setTimeout(undefined,1000)這樣執行了!!!
為了,驗證想法,我們可以改下函數的內容 var count = 1;
var container = document.getElementById('container'); function getUserAction() { container.innerHTML = count++; return `alert('done')`; }; function debounce(f, t) { let tid; return () => {
if(tid) {
clearTimeout(tid);
} tid = setTimeout(f.call(this), t);
}
}
container.onmousemove = debounce(getUserAction, 3000);
果然,出來一個alert!!!!!!!那么,到此也就證明了,我們的定時函數還是執行了的~~~~
總結下,setTimeout()第一個參數還是一個function聲明,不要直接執行function.或者,在一定需要的時候,去讓函數返回這個需要執行的code或function(就和閉包這樣的直接return function).
不說了,還是自己太大意了,哈哈哈哈哈~~~~