草庐IT

javascript - 关闭窗口打破事件循环假设

coder 2024-05-08 原文

我遇到过一个小烦恼,但它会发展成一个大问题。

问题 1: 在 Internet Explorer 中,当您关闭窗口(通过 window.open 打开)时,ownerDocument 将随之消失

这意味着对 DOM 的任何调用,例如 appendChildcreateElement,都将失败并显示 SCRIPT70: Permission DeniedSCRIPT1717:接口(interface)未知

我查看了其他浏览器(例如 Chrome)的行为。在 Chrome 中,ownerDocument 仍然引用 #documentownerDocument.defaultView 最终将是 undefined。这对我来说很有意义。对 appendChildcreateElement 的调用将通过。只要您不尝试直接引用 defaultView,我认为一切都很好。

问题 2: 在 Internet Explorer 中,当您单击生成窗口的关闭按钮时,它似乎不遵守事件循环。我将 unload 事件附加到生成的窗口,它立即触发,而不是在事件循环结束时将其排队。这对我来说有意义。处理这个相当微不足道的问题变得非常不可能。

如果我们只有问题 1,那么会有一个 - 仍然很痛苦但 - 直接的解决方案:检查 ownerDocument 是否存在,如果不存在则跳过。事实上,ownerDocument 在同步 JavaScript 代码中消失了。

预期行为:如果您引用了 DOM 节点,它不应消失 - 垃圾收集完整性。

预期行为 2:DOM 节点不应在同步代码中消失。 (当然除非你删除它)。

已知解决方法:将所有与 DOM 交互的代码移到窗口中,这样当窗口关闭时,JavaScript 运行时环境也会关闭。这不是一个简单的解决方案,可能需要对您的架构进行重大更改。

蹩脚的解决方案:将任何与 DOM 交互的函数包装在一个函数中,如果它检测到元素的窗口已关闭,该函数将消耗错误。这是非常具有侵入性的,并且对性能有重大影响,而 IE 已经很慢了。

有没有更好的解决方案?

至少,我想要的是一种忽略因用户关闭窗口而引发的任何错误的方法。 问题 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/

最佳答案

除非有人有更好的解决方案,否则我将采用蹩脚的解决方案。这是我的代码:

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;
                }
            }
        };
    });
}

wrapped_element 是我为修改 DOM 而返回的 API。我已经将所有函数包装在一个 try-catch 中,如果它发现窗口已关闭,它将忽略错误。我只为行为类似于 Internet Explorer 的浏览器调用此函数。

似乎只有非常小的性能影响。当然,这取决于您调用此 API 的密集程度。

一个小的缺点是目前重新抛出一些错误在一些浏览器中被破坏了。重新抛出 DOMException 会重置 Internet Explorer 和 Chrome(可能还有其他)中的堆栈。我还发现无法从 Internet Explorer 中的 DOMException 获取文件名和行号。又一次,粗略的疏忽最终只会浪费每个人的时间。

关于javascript - 关闭窗口打破事件循环假设,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14895844/

有关javascript - 关闭窗口打破事件循环假设的更多相关文章

  1. ruby - 树顶语法无限循环 - 2

    我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He

  2. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

    我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

  3. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  4. ruby - 如何关闭 ruby​​ gem "Spreadsheet?"中的文件 - 2

    下面的代码在我第一次运行它时就可以正常工作:require'rubygems'require'spreadsheet'book=Spreadsheet.open'/Users/me/myruby/Mywks.xls'sheet=book.worksheet0row=sheet.row(1)putsrow[1]book.write'/Users/me/myruby/Mywks.xls'当我再次运行它时,我会收到更多消息,例如:/Library/Ruby/Gems/1.8/gems/spreadsheet-0.6.5.9/lib/spreadsheet/excel/reader.rb:11

  5. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  6. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

  7. ruby - (Ruby || Python) 窗口管理器 - 2

    我想用这两种语言中的任何一种(最好是ruby​​)制作一个窗口管理器。老实说,除了我需要加载某种X模块外,我不知道从哪里开始。因此,如果有人有线索,如果您能指出正确的方向,那就太好了。谢谢 最佳答案 XCB,X的下一代API使用XML格式定义X协议(protocol),并使用脚本生成特定语言绑定(bind)。它在概念上与SWIG类似,只是它描述的不是CAPI,而是X协议(protocol)。目前,C和Python存在绑定(bind)。理论上,Ruby端口只是编写一个从XML协议(protocol)定义语言到Ruby的翻译器的问题。生

  8. ruby - Ruby 中的闭包和 for 循环 - 2

    我是Ruby的新手,有些闭包逻辑让我感到困惑。考虑这段代码:array=[]foriin(1..5)array[5,5,5,5,5]这对我来说很有意义,因为i被绑定(bind)在循环之外,所以每次循环都会捕获相同的变量。使用每个block可以解决这个问题对我来说也很有意义:array=[](1..5).each{|i|array[1,2,3,4,5]...因为现在每次通过时都单独声明i。但现在我迷路了:为什么我不能通过引入一个中间变量来修复它?array=[]foriin1..5j=iarray[5,5,5,5,5]因为j每次循环都是新的,我认为每次循环都会捕获不同的变量。例如,这绝对

  9. ruby-on-rails - Ruby 的 'open_uri' 是否在读取或失败后可靠地关闭套接字? - 2

    一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我

  10. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

随机推荐