8

我有一个包含外部内容的 iframe 页面。我不希望外部内容中的无限循环使我的整个页面崩溃。有什么办法可以解决这个问题。

我试图设置一些东西,父子 iframe 每隔一段时间发送消息,如果子 iframe 没有响应太长时间,父级更改 iframes src,但这似乎不起作用。一旦 iframe 开始循环,父级的 setTimeout 函数就不再执行。在此处查看我的代码(请注意,如果您执行它会导致您的选项卡崩溃,请在执行前打开控制台以查看日志记录):

<html>
<head>
</head>
<body>
<script type="text/javascript">
var scr = 'script';
var html = '<html><head><script>\n' +
'  window.addEventListener("message", answer, false);' +
'  function answer() { console.log("answered"); parent.postMessage(\'hi\', \'*\');}' +
'  setTimeout("while(1){console.log(\'in loop\')};", 3000)' +
"</" + scr + "></head><body>IFRAME</body</html>";

var lastAnswer = (new Date()).getTime();
var iframe = document.createElement('iframe');
queryChild();

window.addEventListener("message", receive, false);
function receive() {
  lastAnswer = (new Date()).getTime();
  console.log('got answer');
}

function queryChild() {
  console.log('querying');
  if((new Date()).getTime() - lastAnswer > 5000) {
    console.log('killing');
    iframe.src = '';
  } else if(iframe.contentWindow){
    iframe.contentWindow.postMessage('hi', '*');
  }
  setTimeout(queryChild, 2000);
};

document.body.appendChild(iframe);
iframe.contentWindow.document.open();
iframe.contentWindow.document.write(html);
iframe.contentWindow.document.close();


</script>
</body>
</html>

关于如何解决这个问题的任何建议?

4

4 回答 4

5

我对此类问题的经验是,除非您可以在将外部代码提供给iframe(作为 URL 或通过srcdoc属性)之前访问外部代码,否则循环将完全中断任何 JavaScript 执行。

无论你实现什么样的超时功能,它都不会被调用,因为 iframe 代码执行会消耗 100% 的资源,直到浏览器报告崩溃。

您的选择是:

  • 在将代码添加到之前自动清理代码iframe,这被证明是不切实际的,因为有无限的方法可以无限循环,并且您将无法全部捕获它们。您必须编写一个扫描程序脚本,该脚本可以检测无限循环,同时在扫描代码的过程中不会崩溃。
  • 使用像Google Caja这样的沙盒解决方案来清理代码。但是,如果没有大量配置,这将在结构上改变代码。
  • 如果应用程序具有创建虚拟环境和监控它们的能力,您可以执行 iframe 代码(比如说在某种虚拟机上),检查进程是否锁定并使用该结果来确定您是否可以安全地设置属性到您的iframe.src代码的 URL。这可能是唯一可以保证某种保证该代码不会立即锁定的解决方案(但是,有很多方法可以在稍后的执行点产生竞争条件,因此无法确定永远不会锁定浏览器)。

摘要:除非您能找到一种方法在将代码显示在 中之前对其进行广泛测试,否则您iframe不能保证 iframe 代码不会锁定浏览器选项卡。

于 2012-10-08T22:55:59.313 回答
0

尝试这个:

<script>
 document.getElementById('iframeID').onload= function() { //When the iframe loads quickly
     clearTimeout(killerTimer); // Stop the Killer Timer
 };
 var killerTimer = setTimeout( function() {
     document.getElementById("iframeID").setAttribute("src",""); //Otherwise, kill the iframe
 }, 3000 ); 
</script>
于 2012-10-08T22:33:38.327 回答
0

它高度依赖于浏览器,某些浏览器为每个页面(或 iframe)使用一个线程,在这种情况下,您的脚本无法执行,直到 iframe 执行结束(无限循环)。其他一些人每页(或 iframe)有一个线程,也许您可​​以做到。

我敢肯定的是,如果您希望支持企业浏览器(如 IE8),那么您就做不到。

于 2012-10-08T21:37:25.177 回答
0

这个

console.log('killing');
    iframe.src = '';

不会杀的iframe。根据同源策略,您不能从您的域操作外部域。只是更改srcaniframe不会触发iframe. src会改变,但iframe不会被导航。

如果您从内部收到消息,iframe您应该iframe从文档树中删除并在文档树中插入一个新消息,以便使用removeChild

document.body.removeChild(iframe);
document.body.appendChild(newiframe);

看看我在这里创建的这个简单的演示:http: //jsbin.com/avodeb/1/

于 2012-10-08T21:37:51.587 回答