如何检测JavaScript中的死循环示例详解


Posted in Javascript onAugust 30, 2020

前言

如果我们需要执行用户写的代码,如和避免死循环?我们最近遇到了这个问题,因为写错代码很常见,所以我们进行了一下尝试。

如何检测JavaScript中的死循环示例详解

首先我们需要使用iframe

这主要是安全考虑,我们需要一个sandbox环境来执行JavaScript,避免影响到整体。iframe的sandbox属性可以用来禁止弹窗等等,非常有用。

地址可以选择Blob url,不过blob url会持有当前web page的origin,如果用户拷贝一些乱七八糟的代码不小心执行的话,会有安全问题。所以最终决定用data URI。

iframe的执行仍然在同一个thread

iframe中执行了代码,发生死循环的时候,浏览器还是死掉了,因为iframe和parent还是在同一个thread。也就是说,我们无法在parent中进行timeout检测,因为检测代码在死循环发生时永远不会被执行。

Web Worker可行但不支持DOM API

如果是纯粹的JavaScript代码,或许用web worker可以,但是我们需要DOM API,所以Web Worker也不在考虑范围之中。

看来只能修改用户代码了

假设大多数死循环都是由while/for引起的,如果我们能插入一些代码并在每一次循环中进行检测,我们也许就可以根据某些条件提前终止循环。

比如这样的代码

function abc() {
 while (true) {
  console.log(Date.now())
 }
}

如果我们插入一个 __detectInfiniteLoop() 方法,并在while loop里面调用的话,就可以在loop 10000次的时候报错终止执行。

let __count = 0
const __detectInfiniteLoop = () => {
 if (__count > 10000) {
  throw new Error('Infinite Loop detected')
 }
 __count += 1
}

function abc() {
 while (true) {
  console.log(Date.now())
  __detectInfiniteLoop()
 }
}

操作AST在合适位置插入代码

通过字符串匹配来编辑代码细节太复杂容易出错,我们可以用编辑AST的方式,实际上非常简单。

用到babel的3个package。

  1. @babel/parser - parse 代码为AST
  2. @babel/traverse - 搜索 for/while loop
  3. @babel/generator - 生成插入后的代码

首先 parse用户的代码为AST

import { parse } from '@babel/parser'
const ast = parse(code)

然后我们准备一下需要插入的代码。

代码有两部分,第一部分是function定义,实际上可以在头部插入,所以字符串就够了。第二部分是function的调用,这部分需要插入到AST中,所以也需要parse一下。

const prefix = `
 let __count = 0
 const __detectInfiniteLoop = () => {
  if (__count > 10000) {
   throw new Error('Infinite Loop detected')
  }
  __count += 1
 }
`

const detector = parse(`__detectInfiniteLoop()`)

接下来就找到 while/for/do..while 的位置,然后插入detector的调用。

import traverse from '@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中执行。

import generate from '@babel/generator'
const newCode = prefix + generate(ast).code

如何检测JavaScript中的死循环示例详解

如愿以偿!撒花!

最后

这个方法不是完美的,不过满足了我们自己的需求。你可以根据需要进行一下调整。

到此这篇关于如何检测JavaScript中的死循环的文章就介绍到这了,更多相关检测JavaScript死循环内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
jQuery Div中加载其他页面的实现代码
Feb 27 Javascript
ie focus bug 解决方法
Sep 03 Javascript
解决Extjs上传图片无法预览的解决方法
Mar 22 Javascript
JavaScript操作XML文件之XML读取方法
Jun 09 Javascript
JS+CSS实现的日本门户网站经典选项卡导航效果
Sep 27 Javascript
JavaScript兼容浏览器FF/IE技巧
Aug 14 Javascript
jquery  实现轮播图详解及实例代码
Oct 12 Javascript
Node.js中process模块常用的属性和方法
Dec 13 Javascript
JavaScript对象封装的简单实现方法(3种方法)
Jan 03 Javascript
vue基于Element构建自定义树的示例代码
Sep 19 Javascript
判断文字超过2行添加展开按钮,未超过则不显示,溢出部分显示省略号
Apr 28 Javascript
javascript实现扫雷简易版
Aug 18 Javascript
JavaScript中CreateTextFile函数
Aug 30 #Javascript
详解vue组件之间的通信
Aug 30 #Javascript
如何阻止移动端浏览器点击图片浏览
Aug 29 #Javascript
JavaScript事件委托实现原理及优点进行
Aug 29 #Javascript
JS如何判断对象是否包含某个属性
Aug 29 #Javascript
JS获取当前时间戳方法解析
Aug 29 #Javascript
JS PHP字符串截取函数实现原理解析
Aug 29 #Javascript
You might like
php 文件缓存函数
2011/10/08 PHP
php求今天、昨天、明天时间戳的简单实现方法
2016/07/28 PHP
javascript+css 网页每次加载不同样式的实现方法
2009/12/27 Javascript
原生js写的放大镜效果
2012/08/22 Javascript
div拖拽插件——JQ.MoveBox.js(自制JQ插件)
2013/05/17 Javascript
js判断运行jsp页面的浏览器类型以及版本示例
2013/10/30 Javascript
JsRender for object语法简介
2014/10/31 Javascript
AngularJs动态加载模块和依赖注入详解
2016/01/11 Javascript
使用node+vue.js实现SPA应用
2016/01/28 Javascript
JavaScript简单实现弹出拖拽窗口(一)
2016/06/17 Javascript
JavaScript实现隐藏省略文字效果的方法
2017/04/27 Javascript
详解vue-router和vue-cli以及组件之间的传值
2017/07/04 Javascript
vue深入解析之render function code详解
2017/07/18 Javascript
Vue父子模版传值及组件传值的三种方法
2017/11/27 Javascript
web前端vue之vuex单独一文件使用方式实例详解
2018/01/11 Javascript
vue-quill-editor+plupload富文本编辑器实例详解
2018/10/19 Javascript
p5.js临摹动态图形的方法
2019/10/23 Javascript
使用js实现单链解决前端队列问题的方法
2020/02/03 Javascript
[55:03]LGD vs EG 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/18 DOTA
[50:34]VGJ.T vs Fnatic 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
仅用50行Python代码实现一个简单的代理服务器
2015/04/08 Python
python目录与文件名操作例子
2016/08/28 Python
django 修改server端口号的方法
2018/05/14 Python
详解TensorFlow查看ckpt中变量的几种方法
2018/06/19 Python
python flask搭建web应用教程
2019/11/19 Python
Python如何使用字符打印照片
2020/01/03 Python
python生成并处理uuid的实现方式
2020/03/03 Python
如何更换python默认编辑器的背景色
2020/08/10 Python
护士感人事迹
2014/05/01 职场文书
军人离婚协议书样本
2014/10/21 职场文书
建国大业观后感600字
2015/06/01 职场文书
先进个人主要事迹怎么写
2015/11/04 职场文书
2019年聘任书的写作格式及范文!
2019/07/03 职场文书
2019班干部竞选演讲稿范本!
2019/07/08 职场文书
导游词之太行山青龙峡
2020/01/14 职场文书
MySQL索引知识的一些小妙招总结
2021/05/10 MySQL