关于javascript:eslintplugin初体验定时器检测

前言

很久没有写文章了,次要是没什么值得写的。
打工人天天搬砖,的确写无可写。
直到最近整顿团队标准,总算遇到了值得一写的内容。

遇见

整顿代码的时候,在我的项目中发现了很多定时器,比方:

setInterval(() => {
    this.getData()
}, 1e4)

这是定时轮询,更新数据的一段代码。翻了翻历史记录,是个新来的实习生写的。
因为没有把定时器存储起来,天然不可能勾销。
所以每次关上这个组件,就会产生一个定时器,如果用户屡次进入这个页面,那就很蹩脚了。

解决

全局查找setInterval一个个解决,其实问题也不大。我找了下,大略也就百十来个setInterval!当然不会是每个都须要解决,然而一一查看解决,也有点燥人。
所以最初的解决方案是,通过eslint查找,而后对立解决。最次要的是,防止前面的代码持续呈现这种状况。

尝试

网上有很多现成的demo,然而信息大多比拟散乱。比方有的demo版本比拟低,尽管能够运行,我的项目援用就不行。
有的demo不残缺,还须要本人补全。
当然,最次要的还是,我压根没理解过eslint的运行规定……
不得已,查资料,debugger,一步步后退。

AST形象语法树

eslint怎么运行?这就不得不接触到AST的概念。
代码拆解,从语句,语句块,表达式,函数,申明,等等概念,全副拆解到树形构造上,一一映射。
在这篇文章上曾经讲得比拟粗疏:AST形象语法树.

eslint-plugin

eslint-plugin有本人的标准。
咱们要开发一个插件,就必须遵循标准。
恰好是在这个标准上卡了我比拟长时间——整整一天。
我找了相干的demo,本人写了一个例子,查找没有存储的定时器。很快例子就写好了,也通过测试。
于是我就开开心心的发到npm,而后在我的项目中援用,运行代码,所有都很顺利。
然而什么提醒都没有!!!
黑人脸!!!

debugger

在node_modules中调试代码,持续运行。
然而更加奇怪,连我打的debugger都没执行。
一直批改,再运行,还是没有。
如此数次下来,慢慢狐疑人生。
难道是.eslintrc.js配置不对?
天知道,我压根没读过.eslintrc.js的配置,我只是一个搬运工。
好吧,先把.eslintrc.js读一遍。
原来,我真的没有配对.eslintrc.js。。。
一番折腾之后,终于有了提醒 definition for rule 'no-record-time' was not found
好吧,no-record-time是我引入的npm包,持续折腾。
因为开发方式的起因,我须要用以下形式引入:

  plugins: [
    "no-record-time",
  ],
  rules: {
    'no-record-time/no-record-time': 2
  },

解决了这步,信念大增。

而后,我又发现了一个命令npm run lint --debug,这个命令能够间接把eslint运行的后果打印进去,我终于不必改一句代码就重启一次编辑器,锦上添花。
然而,后果很奇怪,我写的规定忽然不失效了。
怎么肥事?

Parser API

开始我用的是Program:exit查找,这是Parser API提供的一个对象,eslint的标准能够返回这个属性,执行所有Program节点的代码遍历。
在测试中,我写的规定能够被很好的运行。然而到了我的项目中,就不行了。
起因未知。
然而我发现了一个更好的对象——ExpressionStatement
这是一个表达式语句对象。
如上文:

setInterval(() => {
    this.getData()
}, 1e4)

这就是一个表达式语句。
如果这样就不是表达式了:

let timer = setInterval(() => {
    this.getData()
}, 1e4)

这是一个申明赋值语句。
所以能够间接查找表达式语句对象。
一通操作,把节点对象打印之后,发现了法则。
node.expression.callee.name这个属性能够读取表达式的函数名,当然,前提是必须有node.expression.callee
那么判断条件就很容易了:

function getSetInterval(node) {
  if (node.expression.callee && node.expression.callee.name === 'setInterval') {
    return false
  }
  if (node.expression.callee && node.expression.callee.name === 'setTimeout') {
    return false
  }
  return true
}

这样就能够找到没存储的定时器了。

残缺代码

/**
 * @fileoverview Rule to flag timer didn't record.
 * @author 陈其文<jianwang19@sina.com>
 * @copyright 2021-01 All rights reserved.
 */
"use strict";

module.exports = {
  meta: {
    type: "problem",

    docs: {
      description: "定时器检测",
      category: "ExpressionStatement",
      recommended: true,
    },

    schema: []
  },
  create: function (context) {
    function getSetInterval(node) {
      if (node.expression.callee && node.expression.callee.name === 'setInterval') {
        return false
      }
      if (node.expression.callee && node.expression.callee.name === 'setTimeout') {
        return false
      }
      return true
    }
    return {
      ExpressionStatement(node){
        let state = getSetInterval(node)
        if (!state) {
          context.report(node, '{{ name }} timer didn\'t record', {
            name: node.expression.callee.name
          });
        }
      },
    };
  },
};

最初发现,其实很简略。
还没通过残缺测试,兴许存在bug。
但究竟是迈出了一大步。
git仓库如下:eslint-plugin-no-record-time

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理