以下代码 clearInterval 为什么不生效?

class Interval {
  constructor() {
    this.timeMap = {};
    this.id = 0;
  }
  setInterval = (cb, time) => {
    this.id++;
    let fn = () => {
      this.timeMap[this.id] = setTimeout(fn, time);
      cb();
    };
    this.timeMap[this.id] = setTimeout(fn, time);
    return this.id; // 返回 this.id
  };
  //改成这样就好了 但是不知道原理
  _setInterval = (cb, time) => {
    let timerId = this.id++;
    let fn = () => {
      this.timeMap[timerId] = setTimeout(fn, time);
      cb();
    };
    this.timeMap[timerId] = setTimeout(fn, time);
    return timerId; // 返回timeId
  };
  clearInterval = (id) => {
    clearTimeout(this.timeMap[id]); // 通过timeMap[id]获取真正的id
    delete this.timeMap[id];
  };
}
let s = new Interval();
// 第一个定时器
let timer = s.setInterval(() => {
  console.log('timer', timer);
}, 1000);
// 第二个定时器
let timer1 = s.setInterval(() => {
  console.log('timer1', timer1);
}, 1000);
// 第三个定时器
let timer2 = s.setInterval(() => {
  console.log('timer2', timer2);
}, 1000);
setTimeout(() => {
  s.clearInterval(timer2); // !!!这里为什么只能清除最后一个定时器, 我传递 timer timer1 就无效
}, 2500);

参考 掘金
https://juejin.cn/post/684490...
刚开始认为 这个 this.id是 非引用类型,应该不会影响~
然后进一步想到 闭包 作用域的定义之类的,但是还是没有想明白.请各位看官 大佬 解读一番!

阅读 4.1k
4 个回答

clearTimeout和setTimeout的实际顺序你稍微打印一下,你就不觉得你的cb时机不太对吗

this.timeMap[this.id] = setTimeout(fn, time);

每次执行setTimeout的时候timeId都是会发生变化的,你写的timer只是第一次执行setTimeout时候的timeId,当然不能用它来清除后面的timeOut了。

ps:链接是掘金,为什么说参考知乎

生效了,cb()之后你又setTimeout了一次,所以看起来像是没生效,自己调试一下就知道了。
这样改一下就对了,不过没啥意思,代码写的太没思路了,知乎那个也是

class Interval {
  constructor() {
    this.timeMap = {};
    this.id = 0;
  }
  setInterval = (cb, time) => {
    let fn = () => {
      if (!cb())
      this.timeMap[this.id] = setTimeout(fn, time);
      else
      this.clearInterval(this.id);
    };
    this.timeMap[this.id] = setTimeout(fn, time);
    return this.id; // 返回timeId
  };
  clearInterval = (id) => {
    clearTimeout(this.timeMap[id]); // 通过timeMap[id]获取真正的id
    delete this.timeMap[this.id];
  };
}
let s = new Interval(),
  i = 0,
  timer = null;
timer = s.setInterval(() => {
  console.log('timer', timer);
  return i++ === 2;
}, 1000);

以下代码足够了,为啥搞那么复杂

let handle;
let i = 0;
const foo = () => {
    handle = setTimeout(() => {
        console.log(i);
        i ++;
        foo();
    }, 1000);
}
foo();
setTimeout(() => {
    clearTimeout(handle);
}, 3000)

或者这样直接把清除的方法返回来

const vsetInterval = (cb, time) => {
    let handle;
    const foo = () => {
        handle = setTimeout(() => {
            cb();
            foo();
        }, time);
    }
    foo();
    return () => clearTimeout(handle);
}
const vclearInterval = vsetInterval(()=>console.log((new Date).valueOf()), 500);
setTimeout(vclearInterval, 5000);

把自己绕进去了

let fn = () => {
    // 这里打印 this.id 已经不对了 所以需要独立一个变量出来
  console.log('id', this.id);
  this.timeMap[this.id] = setTimeout(fn, time);
  cb();
};
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题