IFRAME 间操作外部对象导致 Opera 崩溃

以下崩溃现象在 Opera 9.6 和 Opera 10.0 beta 版本中均有出现,而在 IE6/7、Firefox2/3、Chrome 中均测试正常。

下面来看这个案例:

在一个页面中嵌入了两个 IFRAME,一个 IFRAME 中显示 FLASH,另一个 IFRAME 中放置监控 FLASH 的代码:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<title> Demo </title>
<script type=”text/javascript” src=”swfobject.js”></script>
</head>

<body>
<iframe id=”flashw” name=”flashw” src=”flash.html” style=”width:200px;height:200px;”></iframe>
<iframe src=”monitor.html” style=”width:200px;height:200px;”></iframe>
</body>
</html>

flash.html:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<title> Demo </title>
<script type=”text/javascript” src=”swfobject.js”></script>
</head>
<body>
<div id=”flashzone”></div>
<script type=”text/javascript”>
window.onload=function(){
    var so = new SWFObject(‘flash.swf’, “flash”, “100”, “100”, “9”, “#FF6600”);
    so.addParam(“allowscriptaccess”, “always”);
    so.write(‘flashzone’);
};
</script>
</body>
</html>

monitor.html:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<title> Demo </title>
</head>
<body>
Status:<input id=”status” type=”text” value=”” />

<script type=”text/javascript”>
var f, t;

window.onload=function(){
        t=setInterval(function(){
            try{
                f=parent.flashw.document.getElementById(‘flash’);
                if(!f)return;
                if(!f.getStatus)return;
                clearInterval(t);
                setInterval(function(){
                    try{
                        document.getElementById(‘status’).value=f.getStatus();
                    }catch(e){}
                }, 10);
            }catch(e){}
        }, 100);

};
</script>
</body>
</html>

在监控器 IFRAME 中,不断检测并显示 Flash 的状态,其中 f.getStatus() 是调用 flash 对象的一个方法。

接着在 Opera 中不断刷新页面,就会发生类似“应用程序故障”的问题,Opera 崩溃退出。

通过和网友的讨论,发现问题可能是由于 Opera 对资源释放判断不够完善,导致在页面 unload 时 setInterval 线程还在引用已释放的对象,也就是引用了一个空指针造成的。

解决这个问题,只需要把 setInterval 交给资源所在的窗体来管理即可。将以上 monitor.html 改成以下代码就可以了:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<title> Demo </title>
</head>
<body>
Status:<input id=”status” type=”text” value=”” />

<script type=”text/javascript”>
var f, t;

window.onload=function(){
        t=parent.flashw.setInterval(function(){
            try{
                f=parent.flashw.document.getElementById(‘flash’);
                if(!f)return;
                if(!f.getStatus)return;
                clearInterval(t);
                parent.flashw.setInterval(function(){
                    try{
                        document.getElementById(‘status’).value=f.getStatus();
                    }catch(e){}
                }, 10);
            }catch(e){}
        }, 100);

};
</script>
</body>
</html>

注意,这里指的资源是指类似 Flash 之类的外联的资源,对其它 IFRAME 的 DOM 的操作不会发生崩溃。

— EOF —