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).

不说了,还是自己太大意了,哈哈哈哈哈~~~~

原文地址:https://www.cnblogs.com/mikusnail/p/11401642.html