如何防止JavaScript中的循环导致浏览器或应用程序崩溃?

我正在使用JavaScript在Windows 8.1 App中创建一个实时编辑器。 几乎完成了,但问题是每当我运行这样糟糕的循环或function,然后它会自动挂起或退出。

我用一个循环测试它,如:(它只是一个例子 – 用户可以用自己的方式编写它的循环..)

for(i=0;i<=50000;i++) { for(j=0;j<5000;j++){ $('body').append('hey I am a bug
'); } }

我知道这是任何应用程序或浏览器处理这种循环的最糟糕情况。 所以在这里我希望如果用户使用这样的循环然后我如何处理它,以产生他们的输出?

或者,如果它不能保护我的应用程序的那种循环,如果它对我的应用程序是危险的,所以我提醒用户:

运行此代码段可能会导致应用崩溃!

我有一个想法,如果代码有类似for(i=0;i<=5000;i++)东西,使用正则表达式检查代码然后上面的警告将显示,如何为此做一个正则表达式?

也可以包含C#作为后端

我有2个解决方案:

1。

我的第一个解决方案是定义变量startSeconds=new Date().getSeconds();

然后,使用正则表达式,我将这段代码插入嵌套循环中。

 ;if(startSecond < new Date().getSeconds())break; 

所以它的作用是每次循环运行时,它做两件事:

检查startSecond是否小于当前秒new Date().getSeconds();

例如,startSecond可能是22. new Date()。getSeconds()可能返回24.现在, if condition成功,所以它打破了循环。

大多数情况下,非危险循环应该运行大约2到3秒

for(var i=0;i<30;i++){}将完全运行,但是大循环将运行3到4秒,这是完全可以的。

我的解决方案使用您自己的50000 * 5000示例,但它不会崩溃!

现场演示: http//jsfiddle.net/nHqUj/4

2。

我的第二个解决方案是定义两个变量startmax

Max应该是您愿意运行的最大循环数。 例1000。

然后,使用正则表达式,我将这段代码插入嵌套循环中。

 ;start+=1;if(start>max)break; 

所以它的作用是每次循环运行时,它做两件事:

  1. start的值增加1。

  2. 检查start是否大于max 。 如果是,它会打破循环。

此解决方案也使用您自己的50000 * 5000示例,但它不会崩溃!

更新的演示: http//jsfiddle.net/nHqUj/3

我正在使用的正则表达式(?:(for|while|do)\s*\([^\{\}]*\))\s*\{([^\{\}]+)\}

遗憾的是,如果不对编辑过的代码进行深入而复杂的代码分析,您将无法完全防止错误的JavaScript杀死您的应用程序。 例如,您可以使用从JavaScript构建抽象语法树的库,如果找到某些模式,则不允许代码执行。 但是,可能导致无限循环的模式数量很大,因此查找起来并不简单,而且可能不够强大。

例如,您可以将代码修改为:

 for(i=0;!timeout() && i<=50000;i++) { for(j=0;!timeout() && j<5000;j++){ $('body').append('hey I am a bug
'); } }

我已经“注入”了一个你写的函数调用timeout 。 在那里,它需要能够检测是否应该中止循环,因为脚本运行的时间太长。

但是,这可能是用do-while编写的,因此需要处理这种类型的循环。

例如在紧密循环中使用jQuery并修改DOM意味着尝试将JavaScript隔离到Web Worker的解决方案会很复杂,因为不允许直接操作DOM。 它只能发送/接收“字符串”消息。

如果您使用XAML / C#WebView来托管(和构建)JavaScript编辑器,那么您可以考虑使用一个名为WebView.LongRunningScriptDetected的事件。 检测到长时间运行的脚本时会引发此问题,从而使主机能够在整个应用程序无响应并被终止之前终止脚本。

不幸的是,同样的事件在WinJS项目中可用的x-ms-webview控件中不可用。

一个想法,但不知道你的编辑是什么能够..

如果有些你怎么理解这个循环可能会导致问题(比如一个循环超过200次然后是一个问题),并且对于像用户那样的循环,如果你可以将代码改为下面提供输出那么它将会不要挂。 但坦率地说不确定它是否适合你。

 var j = 0; var inter = setInterval( function(){ if( j<5000 ){ $('#test').append('hey I am a bug
'); ++j; } else { clearInterval(inter); } }, 100 );

也许在第一行注入定时器循环和检查时间。 为每个循环执行此操作。

正则表达式: /for\([^{]*\)[\s]*{/

例:

 /for\([^{]*\)[\s]*{/.test("for(var i=0; i true 

现在,如果您使用replace并在分组中包装for,则可以获得所需的结果。

 var code = "for(var i=0; i maxPossibleTime) {" + "return; // do something here" + "}"; code.replace(textRegex, matchReplace); 

您无法找到用户尝试使用简单正则表达式执行的操作。 可以说,用户写的代码就像……

 for(i=0;i<=5;i++) { for(j=0;j<=5;j++){ if(j>=3){ i = i * 5000; j = j * 5000; } $('body').append('hey I am a bug
'); } }

然后用简单的正则表达式就无法避免这种情况。 因为i的值在一段时间后增加。 因此,解决问题的最佳方法是建立基准。 比如,你的应用程序在连续处理3分钟后挂起(假设,直到你的应用程序达到3分钟的处理时间,运行正常)。 然后,无论用户尝试运行什么代码,您只需在流程前启动计时器,如果流程花费的时间超过2.5分钟,那么您只需在应用程序中终止该流程并向用户发出弹出窗口,说“运行此代码段”可能会崩溃应用程序!’…通过这种方式你甚至不需要正则表达式或validation用户代码,如果它是坏的…

试试这个……可能会帮助……干杯!

让我们假设您在窗口上下文中而不是在工作者中执行此操作。 在每个内部循环中放入一个名为rocketChair的函数。 这个function很简单。 它递增全局计数器并根据全局上限检查该值。 当天花板到达时,rocketChair会立即抛出“从危险代码中弹出”。 此时,您还可以将任何要保留的状态保存到全局状态变量。

将整个应用程序包裹在一个try catch区块中,当火箭椅弹出时,您可以像英雄一样拯救这一天。