JavaScript setTimeOut()方法的一些疑點自己記錄


原由:

  自己剛在研究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).

不說了,還是自己太大意了,哈哈哈哈哈~~~~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM