Hal*_*yon 15 javascript internet-explorer internet-explorer-9
我遇到了一个令人烦恼的小问题.
问题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运行时环境也是如此.这不是一个简单的解决方案,可能需要对您的架构进行重大更改.
Crappy解决方案:在一个函数中包装任何与DOM交互的函数,如果它检测到元素的窗口已经关闭,它将消耗错误.这是非常具有侵略性并且对性能有重大影响,IE已经非常缓慢.
有更好的解决方案吗?
我想要的是,至少可以忽略Error
由于用户关闭窗口而抛出的任何内容.问题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" />
Run Code Online (Sandbox Code Playgroud)
(另存为.html文件)
说明:
这是一个JSFiddle:http://jsfiddle.net/C9p2R/1/
除非有人有更好的解决方案,否则我将采用蹩脚的解决方案。这是我的代码:
function apply_window_close_fix(dom_element, wrapped_element) {
var ignore_errors = false;
dom_element.ownerDocument.defaultView.addEventListener("unload", function () {
ignore_errors = true;
});
return map(wrapped_element, function (key, func) {
return function () {
try {
return func.apply(this, arguments);
} catch (e) {
if (ignore_errors === false) {
throw e;
}
}
};
});
}
Run Code Online (Sandbox Code Playgroud)
wrapped_element
是我返回的用于修改 DOM 的 API。我将所有函数包装在一个 try-catch 中,如果它看到窗口已关闭,它将忽略错误。我仅针对行为类似于 Internet Explorer 的浏览器调用此函数。
似乎只有很小的性能影响。当然这取决于你调用这个API的密集程度。
一个小缺点是,目前在某些浏览器中重新抛出某些错误的功能被破坏。重新抛出 DOMException 会重置 Internet Explorer 和 Chrome(可能还有其他浏览器)中的堆栈。我还发现无法从 Internet Explorer 中的 DOMException 获取文件名和行号。再一次,粗暴的疏忽最终只会浪费每个人的时间。
归档时间: |
|
查看次数: |
1733 次 |
最近记录: |