setTimeout 与 setInterval 的最佳实践
发布于 3 年前 作者 littlee 1222 次浏览 来自 分享
粉丝福利 : 关注VUE中文社区公众号,回复视频领取粉丝福利

TL;DR(太长不看版)

请使用 https://github.com/littlee/eslint-plugin-clean-timer

背景

在 JavaScript 异步编程中,作者经常会写出各种各样的 bug,其中最常见的错误,都是由于忘记清除 setTimeout 或者 setInterval 创建的定时器引起的。

考虑下面这段代码,以一个简单的 Vue 组件为例

<template>
  <div id="app">
    <p>{{ sec }}</p>
  </div>
</template>
<script>
export default {
  data() {
    return {
      sec: 0
    };
  },
  mounted() {
    setInterval(() => {
      this.sec++;
    }, 1000);
  }
};
</script>

组件挂载后,每隔一秒会将 sec 的值加 1,看起来一切正常,但是,当组件被卸载的时候,setInterval 创建的定时器仍然在持续运行。

经验丰富的读者应该能马上想到,我们可以通过在 useEffect 返回的函数中清除这个定时器来修复这个问题。

改善后的代码如下:

<template>
  <div id="app">
    <p>{{ sec }}</p>
  </div>
</template>
<script>
export default {
  data() {
    return {
      sec: 0
    };
  },
  mounted() {
    this.timer = setInterval(() => {
      this.sec++;
    }, 1000);
  },
  beforeDestroy() {
    clearInterval(this.timer);
  }
};
</script>

问题到这里就完美解决了,但是,对于新手来说,常常需要在运行代码之后才会发现这个错误,而且,在一些没有开发者调试工具的环境(例如移动端 webview)下,类似的错误经常被遗漏。

读到这里,有兴趣的读者可以尝试在编辑器中对自己的某个项目源码进行搜索,如果 setIntervalclearInterval 的搜索结果数量不相等,那么,这个项目就很有可能隐藏了类似的错误,同理,也适用于 setTimeoutclearTimeout

因此,作者开发了一款 eslint 插件,让项目在编码期间,就可以消除类似的错误。

解决方法

eslint-plugin-clean-timer

github 地址:https://github.com/littlee/eslint-plugin-clean-timer

使用

第一步,在项目目录中安装 eslint 并初始化(已存在 eslint 配置请跳过这一步)

npm i -D eslint
npx eslint --init

第二步,安装 eslint-plugin-clean-timer

npm i -D eslint-plugin-clean-timer

并添加一下配置到 eslint 配置中,关于配置文件位置请参考 https://eslint.org/docs/user-guide/configuring/

{
  "plugins": ["clean-timer"],
  "rules": {
    "clean-timer/assign-timer-id": 2
  }
}

此时,打开带有定时器代码的文件,我们可以看到编辑器会对相关代码进行提示,以 VSCode 为例,需要安装 ESLint 拓展

image.png

如果修改了配置文件之后没有生效,可以尝试按 Command(Ctrl)+Shift+P,在弹出面板中找到 ESLint: Restart ESLint Server 命令,并按回车键执行

image.png

除此之外,作者还提供了贴心的修复建议,点击 ESLint 提示的 Quick Fix…,执行第一个选项,可以自动插入一个赋值语句

Apr-01-2021 23-17-17.gif

回到顶部