如何检测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判断RadioButtonList和RadioButton中是否有选中项示例
Sep 29 Javascript
可自定义速度的js图片无缝滚动示例分享
Jan 20 Javascript
js类定义函数时用prototype与不用的区别示例介绍
Jun 10 Javascript
函数式 JavaScript(一)简介
Jul 07 Javascript
web前端开发JQuery常用实例代码片段(50个)
Aug 28 Javascript
jquery事件的ready()方法使用详解
Nov 11 Javascript
面试常见的js算法题
Mar 23 Javascript
Angularjs验证用户输入的字符串是否为日期时间
Jun 01 Javascript
js+html5实现侧滑页面效果
Jul 15 Javascript
Vue.js移动端左滑删除组件的实现代码
Sep 08 Javascript
解决vue项目打包后提示图片文件路径错误的问题
Jul 04 Javascript
如何使用 vue + d3 画一棵树
Dec 03 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
2006/10/09 PHP
php中0,null,empty,空,false,字符串关系的详细介绍
2013/06/20 PHP
php Imagick获取图片RGB颜色值
2014/07/28 PHP
ThinkPHP查询返回简单字段数组的方法
2014/08/25 PHP
PHP数据库编程之MySQL优化策略概述
2017/08/16 PHP
thinkPHP5实现的查询数据库并返回json数据实例
2017/10/23 PHP
js 页面输出值
2008/11/30 Javascript
网页运行时提示对象不支持abigimage属性或方法
2014/08/10 Javascript
jQuery焦点图插件SaySlide
2015/12/21 Javascript
Angularjs过滤器使用详解
2016/05/25 Javascript
JS触发服务器控件的单击事件(详解)
2016/08/06 Javascript
JS实现拖动滚动条评分的效果代码分享
2016/09/29 Javascript
微信小程序实现animation动画
2018/01/26 Javascript
JS实现的JSON数组去重算法示例
2018/04/11 Javascript
彻底弄懂 JavaScript 执行机制
2018/10/23 Javascript
[52:00]2018DOTA2亚洲邀请赛 4.1 小组赛 A组加赛 LGD vs Optic
2018/04/02 DOTA
python实现登陆知乎获得个人收藏并保存为word文件
2015/03/16 Python
多版本Python共存的配置方法
2017/05/22 Python
django 微信网页授权登陆的实现
2019/07/30 Python
ubuntu上安装python的实例方法
2019/09/30 Python
pytorch中的上采样以及各种反操作,求逆操作详解
2020/01/03 Python
Python中join()函数多种操作代码实例
2020/01/13 Python
python实现同一局域网下传输图片
2020/03/20 Python
django rest framework serializer返回时间自动格式化方法
2020/03/31 Python
Python子进程subpocess原理及用法解析
2020/07/16 Python
python实现无边框进度条的实例代码
2020/12/30 Python
详解Python中的Lock和Rlock
2021/01/26 Python
浅析HTML5 Landmark
2020/09/11 HTML / CSS
英国办公用品商店:Office Outlet
2018/04/04 全球购物
韩国保养品、日本药妆购物网:小三美日
2018/12/30 全球购物
荷兰家电购物网站:Expert.nl
2020/01/18 全球购物
应届大专毕业生个人自荐信
2013/09/22 职场文书
信息管理员岗位职责
2013/12/01 职场文书
岗位标兵事迹材料
2014/05/17 职场文书
乡镇安全生产月活动总结
2015/05/08 职场文书
分享node.js实现简单登录注册的具体代码
2022/04/26 NodeJs