永无止境的“连接” AJAX 表单提交后的消息

发布于 2024-12-02 19:42:56 字数 2362 浏览 0 评论 0原文

我有一个类,它允许通过 AJAX 提交具有文件类型输入的表单。它创建一个隐藏的 IFRAME 元素,更改表单 target 属性,以便它提交到 IFRAME,提交表单,然后将目标更改回来原来如此。它还向 IFRAME 添加了一个 onLoad 事件,以便我可以获得回调。在触发我的回调函数之前,onLoad 函数还会从页面中删除 IFRAME

该课程运行良好,我按预期得到了回调。在 Firebug 的网络面板中,我看到了请求,也看到了响应,一切都很好。但是,一旦开始提交,页面的浏览器选项卡就会通过加载微调器更改为“正在连接”,并且永远不会变回原样。它使选项卡看起来正在加载,如果我保持浏览器打开,这将持续

困扰我的永无休止的“连接”消息

那么问题是:有什么办法吗让我手动停止此操作,或者是否有其他方法可以阻止它启动?

以下是从网络面板中获取的响应标头:

Date    Fri, 02 Sep 2011 15:23:15 GMT
Server  Apache/2.2.10 (Win32) PHP/5.3.1
X-Powered-By    PHP/5.3.1
Expires Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control   no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma  no-cache
Set-Cookie  PHPSESSID=agncdnha86mtci7dmuvriobak2; path=/
Content-Length  165
Keep-Alive  timeout=5, max=100
Connection  Keep-Alive
Content-Type    text/html

以及下面的网络面板的捕获。 POST是由表单的提交引起的,GET是由回调函数引起的,它是改变页面上图像的来源。

Firebug's Net panel

这不是特定于本页面的,它发生在我使用此技术提交文件/图像的任何地方通过 IFRAME。这会影响我当前版本的 Firefox (6.0),但也会影响以前的版本(5.x、4.x、3.x)。事实上,IFRAME 在加载后从页面中删除,这使得这尤其令人困惑 - 即使请求从未完成,删除该元素应该有效地终止/停止并“连接”浏览器认为的正在发生。

更新 根据 @Sidncious 的回答,我向回调函数添加了超时,以引入延迟删除 IFRAME 元素。我试验了延迟的长度,即使是1ms的延迟也足够了。这当然可以作为一种解决方法,但我仍然想知道是否有人可以阐明其原因,最好是避免一起使用超时。我在下面添加了修改后的代码(带有超时),以防有帮助。这是 IFRAMEonLoad 事件(io 我们是对框架元素的引用):

        var obj={};
        var success = true;
        try{
            obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
            obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
        }
        catch(e){ success = false; }
        if( success ){
            this.fireEvent('onSuccess', obj.responseText );
        }else{
            this.fireEvent('onFailure', obj );
        }
        this.fireEvent('onComplete', obj );
        io.removeEvent('load', uploadCallback );
        setTimeout(function () { // <--- this timeout prevents the issue
            io.dispose();
        }, 1);

I have a class which enables forms with a file-type input to be submitted via AJAX. It creates a hidden IFRAME element, changes the form target property so that it submits to the IFRAME, submits the form, then changes the target back to what it was. It also adds an onLoad event to the IFRAME so I can get a callback. The onLoad function also removes the IFRAME from the page before firing my callback function.

The class works perfectly, I get the callback as expected. In Firebug's Net panel, I see the request, I see the response, all is well. But, as soon as the submit starts, the browser tab for the page changes to "Connecting" with the loading spinner and never changes back. It makes the tab appear to be loading, this will go on for days if I leave the browser open.

The never-ending "Connecting" message that plagues me

The question, then, is: Is there any way for me to stop this manually, or is there some other way that I can prevent it from starting?

Here are the Response Headers as taken from the Net panel:

Date    Fri, 02 Sep 2011 15:23:15 GMT
Server  Apache/2.2.10 (Win32) PHP/5.3.1
X-Powered-By    PHP/5.3.1
Expires Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control   no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma  no-cache
Set-Cookie  PHPSESSID=agncdnha86mtci7dmuvriobak2; path=/
Content-Length  165
Keep-Alive  timeout=5, max=100
Connection  Keep-Alive
Content-Type    text/html

And a capture of the Net panel below. The POST is from the submission of the form, the GET is caused by the callback function, it is changing the source of an image on the page.

Screenshot of Firebug's Net panel

This is not specific to this page, it happens anywhere I use this technique to submit a file/image via an IFRAME. This affects my current version of Firefox (6.0), but also affected previous versions (5.x, 4.x, 3.x). The fact that the IFRAME is removed from the page after it loads makes this especially baffling - even if the request never finished, the removal of the element should effectively kill/stop and "connecting" that the browser thinks is happening.

UPDATE
Per the answer from @Sidnicious, I added a timeout to the callback function to introduce a delay in removal of the IFRAME element. I experimented with the length of the delay, even a 1ms delay is adequate. This certainly qualifies as a work-around, but I'd still like to know if anyone can shed some light on to the why of it, preferably leading to an avoidance of using the timeout all together. I've included the modified code (with the timeout) below, in case it is helpful. This is the onLoad event for the IFRAME (io us a reference to the frame element):

        var obj={};
        var success = true;
        try{
            obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
            obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
        }
        catch(e){ success = false; }
        if( success ){
            this.fireEvent('onSuccess', obj.responseText );
        }else{
            this.fireEvent('onFailure', obj );
        }
        this.fireEvent('onComplete', obj );
        io.removeEvent('load', uploadCallback );
        setTimeout(function () { // <--- this timeout prevents the issue
            io.dispose();
        }, 1);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

若沐 2024-12-09 19:42:56

更新:Firefox 错误现已标记为“已修复”,并将在不久的将来进行更新。


我也遇到过这个问题,并且希望看到根本原因得到解决。

  • 我与几位 Firefox 开发人员(mbrubeck 和 gavin)交谈过,他们认为这是一个错误! 2005 年 Firefox 1.9 报告并修复了相同的问题。然后,bug 489259 在 2009 年被公开。mbrubeck 慷慨地将其移出“未经证实”的一堆。

  • Safari 的表现比 Firefox 更好,但如果您在 load 事件期间删​​除 iframe,状态栏中会显示一条错误消息(“打开页面时出现错误...”)。我发现自 2007 年以来一直存在的两个类似的 WebKit bug:1548513281

当您在 load 事件期间从文档中删除 iframe 时,就会发生这种情况。 JavaScript 事件同步触发——也就是说,与浏览器自己对网页的处理串联。这就是为什么可以阻止提交表单或阻止从事件处理程序中注册按键或鼠标单击。

上次在 Firefox 中修复此错误时,原因是从页面中删除 iframe 使其忘记哪个页面拥有它,但 iframe 通知页面: load 事件之后完成加载。

您使用 setTimeout 安排的任何事情都会在事件循环的当前周期之后发生 - 在浏览器完成当前正在执行的操作之后。因此,使用 setTimeout 删除 iframe,即使超时为零,也可以让它完成:

iframe.onload = function(){
    // Do work with the content of the iframe…

    setTimeout(function(){
        iframe.parentNode.removeChild(iframe);
    }, 0);
}

您可以找到正在使用的这项技术 在 jQuery 表单插件中

Update: the Firefox bug is now marked as “fixed” and will make it into a near-future update.


I’ve run into this too and would love to see the root cause fixed.

  • I talked to a couple of Firefox developers (mbrubeck and gavin), and they think that it’s a bug! The same issue was reported, and fixed, in 2005 for Firefox 1.9. Then, bug 489259 was opened in 2009. mbrubeck has graciously moved it out of the “unconfirmed” pile.

  • Safari behaves better than Firefox, but an error message (“One error in opening the page…”) shows up in the status bar if you remove the iframe during the load event. I found two similar WebKit bugs which have been open since 2007: 15485 and 13281.

This appears to happen when you remove an iframe from the document during the load event. JavaScript events fire synchronously — that is, in series with the browser’s own handling of the web page. That’s why it's possible to prevent a form from being submitted or prevent a keypress or mouse click from being registered from within an event handler.

The last time this bug was fixed in Firefox, the cause was that the removing an iframe from the page makes it forget which page owned it, but the iframe notifies the page that it was finished loading after the load event.

Anything you schedule with setTimeout happens after the current cycle of the event loop — after the browser finishes what it’s doing right now. So, using setTimeout to remove the iframe, even with a timeout of zero, lets it finish:

iframe.onload = function(){
    // Do work with the content of the iframe…

    setTimeout(function(){
        iframe.parentNode.removeChild(iframe);
    }, 0);
}

You can find this technique in use in the jQuery form plugin.

英雄似剑 2024-12-09 19:42:56

IFRAME 中的 onload 事件未完全执行,因为它会因 IFRAME 的删除而中断。
Firefox 有一个错误,它在中断 onload 事件后不会调用其内部代码。

通过设置超时,Firefox 会干净地执行 onload,之后运行超时回调并删除 IFRAME。根据文档,当页面 (或操作系统/浏览器本身)正忙于其他任务(即删除 IFRAME)。

The onload event in your IFRAME is not executed completely, because it gets interrupted by the removal of your IFRAME.
Firefox has a bug, where it does not call it's internal code after interrupting the onload event.

By setting the timeout, Firefox cleanly executes the onload, after which your timeout callback is run and the IFRAME is removed. According to the documentation, the timeout can also fire later when the page (or the OS/browser itself) is busy with other tasks (i.e. removing the IFRAME).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文