当前位置: 首页 > 后端技术 > Node.js

eslint-plugin初体验——定时器检测

时间:2023-04-03 10:07:54 Node.js

前言好久没有写文章了,主要是没有什么值得写的。工人天天搬砖,实在没什么好写的。直到最近整理团队规范,终于发现了值得写的东西。遇到整理代码的时候,发现项目中有很多定时器,比如:setInterval(()=>{this.getData()},1e4)这是一段定时轮询更新数据的代码。翻开历史记录,是一个新来的实习生写的。因为定时器没有存储,自然不可能取消。所以每次打开这个组件,都会产生一个定时器,如果用户多次进入这个页面,那就不好了。解决全局搜索setInterval一一处理,其实问题不大。我找到了,大概有一百个setIntervals!当然,并不是所有的都需要解决,但是一个一个的去查,一个一个解决,还是有点乏味的。所以最后的解决办法就是通过eslint找到,然后统一解决。最重要的是避免这种情况在后面的代码中继续下去。网上有很多现成的demo,但是大部分资料都是零散的。比如一些demo版本比较低,虽然可以运行,但是工程引用不行。有些demo不完整,需要自己补全。当然,最重要的是,我一直没搞懂eslint的运行规则。。。不得已,查了资料,debugger,一步步往前走。AST抽象语法树eslint是如何工作的?这就不得不接触到AST的概念了。代码反汇编,从语句、语句块、表达式、函数、声明等概念,全部反汇编成树状结构,一一映射。在这篇文章:AST抽象语法树中已经有详细的介绍。eslint-pluginslint-plugin有自己的规范。如果我们要开发一个插件,我们必须遵循规范。正是这个规范困扰了我很长时间——一整天。找了相关的demo,写了一个例子来查找没有存储的定时器。很快就编写并测试了这个例子。于是高高兴兴发到npm,然后在项目中引用,运行代码,一切顺利。但是没有任何提示!!!黑人脸!!!调试器调试node_modules中的代码并继续运行。但更奇怪的是,连我敲的调试器都没有执行。不断修改,再次运行,还是不行。经历了这么多次,我渐渐怀疑人生。会不会是.eslintrc.js配置不对?天知道,我根本没看过.eslintrc.js配置,我只是一个搬运工。好吧,先阅读.eslintrc.js。事实证明,我并没有真正配对.eslintrc.js。..折腾了一番,终于得到了提示definitionforrule'no-record-time'wasnotfound。嗯,no-record-time就是我介绍的npm包,继续折腾。由于开发方式的原因,我需要通过以下方式导入:plugins:["no-record-time",],rules:{'no-record-time/no-record-time':2},this步骤解决了,信心大增。然后,我找到了另一个命令npmrunlint--debug,可以直接打印出eslint运行的结果。我终于重启了编辑器,一行代码都没改,就更厉害了。然而,结果很奇怪,我写的规则突然不起作用了。怎么了?在ParserAPI的开头,我使用了Program:exitsearch,这是ParserAPI提供的一个对象。eslint规范可以返回这个属性,执行所有Program节点的代码遍历。在测试中,我编写的规则运行良好。但是到了项目上,就不行了。原因不明。但是我找到了一个更好的对象——ExpressionStatement。这是一个表达式语句对象。如上:setInterval(()=>{this.getData()},1e4)这是一个表达式语句。如果这不是一个表达式:lettimer=setInterval(()=>{this.getData()},1e4)这是一个语句赋值语句。所以可以直接查找表达式语句对象。一次通过操作,打印节点对象后,找到规则。属性node.expression.callee.name可以读取表达式的函数名。当然前提是必须有node.expression.callee。那么就很容易判断条件了:.expression.callee.name==='setTimeout'){returnfalse}returntrue}这样就可以找到没有存储的定时器。完整代码/***@fileoverview标记计时器的规则没有记录。*@作者陈启文*@copyright2021-01版权所有。*/"usestrict";module.exports={meta:{type:"problem",docs:{description:"TimerDetection",category:"ExpressionStatement",recommended:true,},schema:[]},创建:function(context){functiongetSetInterval(node){if(node.expression.callee&&node.expression.callee.name==='setInterval'){returnfalse}if(node.expression.callee&&node.expression.callee.name==='setTimeout'){returnfalse}returntrue}return{ExpressionStatement(node){letstate=getSetInterval(node)if(!state){context.report(node,'{{name}}计时器没有记录',{name:node.expression.callee.name});}},};},};最后发现其实很简单。尚未完全测试,可能包含错误。但这毕竟是一大步。git仓库如下:eslint-plugin-no-record-time