停止浏览器“厄运的悸动”;加载 comet/服务器时推送 XMLHttpRequest

发布于 2024-08-11 08:04:36 字数 939 浏览 2 评论 0原文

(这个问题类似于这个,但它是为了使用 XMLHttpRequest 而不是 Comet 的 iframe。)

我正在启动一个异步长轮询,如下所示:

var xhr = new XMLHttpRequest();
xhr.open('POST', url);
xhr.send();

如果我在 < 中执行此操作/code> 在头部,它将导致文档永远保持加载。 (我正在 Mac OS X 和 iPhone 上的 Safari 中对此进行测试,它是我需要支持的唯一浏览器)。

使用 DOMContentLoadedload 事件将不起作用。

使用具有足够大延迟的 setTimeout 是可行的。 0 不会,1000 会,100 有时会,有时不会。我对此感到不舒服。

我发现有效的唯一方法是两者的结合:

document.addEventListener('DOMContentLoaded', function () {
    setTimeout(function () {
        var xhr = new XMLHttpRequest();
        xhr.open('POST', url);
        xhr.send();
    }, 0);
});

我想这暂时解决了问题,但我仍然担心它将来会崩溃。 // 编辑:这不会工作也可靠。

有谁知道更可靠的方法吗?

(This question is similar to this one, but it's for using XMLHttpRequest instead of an iframe for Comet.)

I'm starting an async long poll like this:

var xhr = new XMLHttpRequest();
xhr.open('POST', url);
xhr.send();

If I do this inside <script>...</script> in the head, it will cause the document to keep loading forever. (I'm testing this in Safari on Mac OS X and the iPhone, and it's the only browser I need to support).

Using DOMContentLoaded or load events won't work.

Using a setTimeout with a large enough delay will work. 0 won't, 1000 will, 100 will some times and not other times. I don't feel comfortable with this.

The only way I found that works is the combination of both:

document.addEventListener('DOMContentLoaded', function () {
    setTimeout(function () {
        var xhr = new XMLHttpRequest();
        xhr.open('POST', url);
        xhr.send();
    }, 0);
});

I guess this solves the problem for now, but I'm still afraid it will break in the future. // Edit: this doesn't work reliably either.

Does anyone know of a more reliable way?

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

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

发布评论

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

评论(4

悲歌长辞 2024-08-18 08:04:36

我不确定,但似乎如果浏览器显示它仍在下载,那么这是完全正确的 - 这不是彗星编程的本质吗?服务器仍在发送未缓冲的内容,当该内容在 JavaScript 块中传输时,它会被执行,从而允许服务器将事件推送到客户端浏览器。

在 Ajax 早期(例如在 IE6 上,XMLHttpRequest 是一个单独的 ActiveX 对象),我希望浏览器不知道它仍在等待。

但在 Safari 4、Chrome、FX3.5 和所有现代浏览器中,XMLHttpRequest 是内置的 - 它知道它仍在等待服务器仍然流式传输其内容,就像使用和 < code>

简而言之 - 我希望任何 Comet 方法都能显示浏览器仍在下载,因为它确实在下载。我希望您找到的任何解决方法都能在未来的版本中得到修复,因为 Comet 本质上是一种让服务器推送模型正常工作的 hack。

然而,他们已经开始在 HTML 5 中构建真正的服务器推送支持。

移动 Webkit 是否支持 HTML 5 草案event-source 标记了吗?如果是这样,您可以尝试一下。

然后你会得到这样的东西:

<!-- new HTML 5 tag supporting server-push -->
<event-source src="http://myPushService.com" id="service">

<script type="text/javascript">

    function handleServiceEvent(event) {
        // do stuff
    }

    // tell browser to fire handleServiceEvent in response to server-push
    document.getElementById('service').addEventListener('event name', handleServiceEvent, false);
</script>

I'm not sure, but it seems that if the browser shows that it's still downloading then that's entirely correct - isn't that basically what Comet programming is? The server is still sending unbuffered content and when that streams in a block of javascript it's executed, allowing the server to push events to the client browser.

In the Ajax early days (for instance on IE6 where XMLHttpRequest was a separate ActiveX object) I'd of expected the browser to not know that it was still waiting.

But in Safari 4, Chrome, FX3.5 and all the modern browsers the XMLHttpRequest is built in - it knows that it's still waiting for the server to still stream its content, exactly as it would with and <IFrame>

In short - I'd expect any Comet approach to show that the browser was still downloading because it is. I'd expect any workaround you find to get fixed in future builds because Comet is essentially a hack to get a server-push model working.

However they have started to built real server-push support into HTML 5.

Does mobile Webkit support the HTML 5 draft event-source tag yet? If so you could potentially try that.

Then you would have something like this:

<!-- new HTML 5 tag supporting server-push -->
<event-source src="http://myPushService.com" id="service">

<script type="text/javascript">

    function handleServiceEvent(event) {
        // do stuff
    }

    // tell browser to fire handleServiceEvent in response to server-push
    document.getElementById('service').addEventListener('event name', handleServiceEvent, false);
</script>
殤城〤 2024-08-18 08:04:36

当你说:

...这将导致文档永远持续加载。

你这到底是什么意思?你的意思是进度条永远不会结束吗?或者实际文档甚至不完全可见? AJAX 请求不太可能阻止整个文档加载,但无论如何...

情况 1:进度条永远不会完成

这可能是由于 AJAX 请求永远不会完成造成的。您是否尝试过在 Firebug 控制台中查看 AJAX 请求?它将向您显示发出的请求和服务器的响应。我将从这里开始只是为了确保服务器正在发回一些东西。

情况 2:文档元素未完全加载/可见

您可以尝试将

当您执行此操作时,DOM 在脚本执行之前就已完全加载,您不必等待“domready”或“onload”触发。另外,请记住,正在加载的 DOM tree 并不意味着 DOM content (例如图像)已完全加载(您需要等待“onload”)当然)

无论哪种情况,我都会尝试将脚本放在 之前。标签,这样 DOM 骨架就有机会被构建。

旁注:

您是否使用任何类型的调试器查看页面? (Firebug、Webkit 检查器)。如果您打开控制台并且遇到 JavaScript 错误,Webkit Inspector 实际上会停止整个文档的处理。您在控制台中看到任何 JavaScript 错误吗?如果关闭调试器,页面会加载吗?

When you say:

...it will cause the document to keep loading forever.

What exactly do you mean by this? Do you mean that the progress bar never finishes? Or is the actual document not even fully visible? It's not likely that an AJAX request would stop the entire document from loading, but anyway ...

Case 1: The progress bar never finishes

This is likely caused by the AJAX request never completing. Have you tried looking at the AJAX request in a Firebug console? It will show you both the request made and the server's response. I would start here just to make sure the server is sending something back.

Case 2: The document elements are not fully loaded/visible

You can try putting your <script> tag right before the </body> tag.

When you do this, the DOM tree is fully loaded before the script even executes, you don't have to wait for 'domready' or 'onload' to fire. Also, keep in mind that the DOM tree being loaded does not mean DOM content (such as images) have fully loaded (you would need to wait for 'onload' to be sure of that)

In either case, I would try putting the script right before the </body> tag, so the DOM skeleton has a chance to be built.

Side note:

Are you viewing your page with any type of debugger? (Firebug, Webkit Inspector). Webkit Inspector in particular will actually stop the entire document from processing if you have the console open AND a JavaScript error is encountered. Do you see any JavaScript errors in the console? Does the page load if you turn off your debuggers?

ま昔日黯然 2024-08-18 08:04:36

您可以尝试使用 load 事件而不是 DOMContentLoaded 事件吗?它应该会有所不同,因为它仅在页面完全加载时被调用。

var xhr;
document.addEventListener('load', function () {
    xhr = new XMLHttpRequest();
    xhr.open('POST', url);
    xhr.send();
});

这应该有效。不过,我不经常使用Comet,所以目前我没有任何方法来测试它。

编辑:抱歉,刚刚看到马特已经说过了。

Could you try to use the load event instead of the DOMContentLoaded event. It should make a difference as it's only called when the page is completely loaded.

var xhr;
document.addEventListener('load', function () {
    xhr = new XMLHttpRequest();
    xhr.open('POST', url);
    xhr.send();
});

This should work. However, I don't work with Comet very often, so I don't have any way to test it at the moment.

EDIT: Sorry, just saw that Matt had already said this.

暖风昔人 2024-08-18 08:04:36

看起来在某些浏览器中,open(...)方法默认同步发送ajax请求,如果不指定第三个参数?尝试:

xhr.open('POST', url, true);

显式使调用异步。

It looks like in some browsers, the open(...) method sends ajax request synchronously by default, if no third parameter is specified? Try:

xhr.open('POST', url, true);

to explicitly make the call asynchronous.

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