如何检测JavaScript中的死循环示例详解
前言
如果我们需要执行用户写的代码,如和避免死循环?我们最近遇到了这个问题,因为写错代码很常见,所以我们进行了一下尝试。
首先我们需要使用iframe
这主要是安全考虑,我们需要一个sandbox环境来执行JavaScript,避免影响到整体。iframe的sandbox属性可以用来禁止弹窗等等,非常有用。
地址可以选择Bloburl,不过bloburl会持有当前webpage的origin,如果用户拷贝一些乱七八糟的代码不小心执行的话,会有安全问题。所以最终决定用dataURI。
iframe的执行仍然在同一个thread
iframe中执行了代码,发生死循环的时候,浏览器还是死掉了,因为iframe和parent还是在同一个thread。也就是说,我们无法在parent中进行timeout检测,因为检测代码在死循环发生时永远不会被执行。
WebWorker可行但不支持DOMAPI
如果是纯粹的JavaScript代码,或许用webworker可以,但是我们需要DOMAPI,所以WebWorker也不在考虑范围之中。
看来只能修改用户代码了
假设大多数死循环都是由while/for引起的,如果我们能插入一些代码并在每一次循环中进行检测,我们也许就可以根据某些条件提前终止循环。
比如这样的代码
functionabc(){ while(true){ console.log(Date.now()) } }
如果我们插入一个__detectInfiniteLoop()方法,并在whileloop里面调用的话,就可以在loop10000次的时候报错终止执行。
let__count=0 const__detectInfiniteLoop=()=>{ if(__count>10000){ thrownewError('InfiniteLoopdetected') } __count+=1 } functionabc(){ while(true){ console.log(Date.now()) __detectInfiniteLoop() } }
操作AST在合适位置插入代码
通过字符串匹配来编辑代码细节太复杂容易出错,我们可以用编辑AST的方式,实际上非常简单。
用到babel的3个package。
- @babel/parser-parse代码为AST
- @babel/traverse-搜索for/whileloop
- @babel/generator-生成插入后的代码
首先parse用户的代码为AST
import{parse}from'@babel/parser' constast=parse(code)
然后我们准备一下需要插入的代码。
代码有两部分,第一部分是function定义,实际上可以在头部插入,所以字符串就够了。第二部分是function的调用,这部分需要插入到AST中,所以也需要parse一下。
constprefix=` let__count=0 const__detectInfiniteLoop=()=>{ if(__count>10000){ thrownewError('InfiniteLoopdetected') } __count+=1 } ` constdetector=parse(`__detectInfiniteLoop()`)
接下来就找到while/for/do..while的位置,然后插入detector的调用。
importtraversefrom'@babel/traverse' traverse(ast,{ ForStatement:function(path){ path.node.body.body.push(...detector.program.body) }, WhileStatement:function(path){ path.node.body.body.push(...detector.program.body) }, DoWhileStatement:function(path){ path.node.body.body.push(...detector.program.body) } })
AST修改好了,最后一步就是生成最终的代码,然后放到iframe中执行。
importgeneratefrom'@babel/generator' constnewCode=prefix+generate(ast).code
如愿以偿!撒花!
最后
这个方法不是完美的,不过满足了我们自己的需求。你可以根据需要进行一下调整。
到此这篇关于如何检测JavaScript中的死循环的文章就介绍到这了,更多相关检测JavaScript死循环内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。