【发布时间】:2013-02-15 13:28:24
【问题描述】:
我遇到了一个小烦恼,后来演变成一个大问题。
问题 1: 在 Internet Explorer 中,当您关闭一个窗口(通过 window.open 打开的)时,ownerDocument 将随之消失。
这意味着任何对 DOM 的调用,例如 appendChild 或 createElement,都会失败并返回 SCRIPT70: Permission Denied 或 SCRIPT1717: The interface is unknown。
我查看了其他浏览器(例如 Chrome)的行为。在 Chrome 中 ownerDocument 仍然引用 #document 但 ownerDocument.defaultView 最终将是 undefined。这对我来说很有意义。对appendChild 和createElement 的调用将通过。只要您不尝试直接引用defaultView,我认为一切都很好。
问题 2: 在 Internet Explorer 中,当您单击生成窗口的关闭按钮时,它似乎不尊重事件循环。我将unload 事件附加到生成的窗口,它会立即触发,而不是在事件循环结束时对其进行排队。这对我来说不有意义。处理这个相当琐碎的问题变得非常不可能。
如果我们只是遇到问题 1,将会有一个 - 仍然很痛苦但 - 直接的解决方案:检查 ownerDocument 是否存在,如果不存在则跳过。因为它是 ownerDocument 在同步 JavaScript 代码中间消失。
预期行为:如果您引用了 DOM 节点,它不应该消失 - 垃圾回收。
预期行为 2: DOM 节点不应在同步代码中消失。 (当然,除非你删除它)。
已知的解决方法:将所有与 DOM 交互的代码移到窗口中,这样当窗口关闭时 JavaScript 运行时环境也会关闭。这不是一个简单的解决方案,可能需要对您的架构进行重大更改。
糟糕的解决方案: 将任何与 DOM 交互的函数包装在一个函数中,如果它检测到元素的窗口已关闭,则会消耗错误。这是相当侵入性的,对性能有很大影响,而且 IE 已经很慢了。
有没有更好的解决方案?
我想要的至少是一种忽略由于用户关闭窗口而引发的任何Errors 的方法。 问题 1 和 问题 2 打破了您对 JavaScript 代码所做的基本假设:垃圾收集和事件循环。
演示脚本
<script type="text/javascript">
function go() {
var popup = window.open('', 'open', 'width=500,height=300,scrollbars=yes,resizable=yes');
popup.document.open();
popup.document.write('<html><head></head><body></body></html>');
popup.document.close();
for (var i = 0; i < 10000; i += 1) {
var node = popup.document.createTextNode(i + " ");
popup.document.body.appendChild(node);
}
}
</script>
<input type="button" onclick="go();" value="Open popup" />
(另存为.html文件)
说明:
- 在 Internet Explorer 9 中打开
- 点击“打开弹窗”
- 在渲染时关闭窗口
- 观察“权限被拒绝”
这是一个 JSFiddle:http://jsfiddle.net/C9p2R/1/
【问题讨论】:
-
所有 IE 版本都会出现这种情况吗?
-
出现在 IE9 中。我不敢测试旧版本。我不知道IE10。
-
Chrome 允许您修改关闭窗口的 DOM,只要您持有对它的引用,我是否理解正确?你想在 IE 中实现这种行为吗?
-
“ownerDocument 在同步 JavaScript 代码中间消失了” - 你怎么有这么长时间运行的同步代码,你可以在执行期间关闭一个窗口?
-
@Bergi 是的,您可以在 Chrome 中保留对
DOM#document的引用(据我所知,无限期)。 “长时间运行”是相对的,但 IE9 很慢。在 Chrome 中运行不到 2 秒的脚本在 IE9 中大约需要 20 秒。只需重复这些步骤,我就可以轻松地延长执行时间。当我查看 Chrome 中的行为时,我发现它确实尊重事件循环的预期行为。 Window 可能会在视觉上消失,但 JavaScript 在完成较早的事件之前不会收到unload事件(应该如此)。
标签: javascript internet-explorer internet-explorer-9