【问题标题】:How xmlhttprequest objects are created, merged, and destroyed in JavascriptJavascript 中如何创建、合并和销毁 xmlhttprequest 对象
【发布时间】:2012-12-10 15:07:21
【问题描述】:

我的背景是传统的编译型面向对象语言,例如 C++ 和 .NET 编程,现在我正在为一个新项目涉足一些 JavaScript。我在涉足 AJAX 并遇到了一个令人困惑的方面,即浏览器如何管理对象。

[编辑 #2] - 活动内容脚本的更改

我有一个包含三个按钮的练习页面,每个按钮使用XMLHttpRequest 对象更新<textarea>:

  1. 按钮 1 使用 slowtime.php 中的文本内容更新 TextArea1
  2. 按钮 2 使用 slowtime.php 中的文本内容更新 TextArea2
  3. 按钮 3 使用 fasttime.php 中的文本内容更新 TextArea3

slowtime.php 和 fasttime.php 是简单的脚本,它们返回一个带有两个时间戳的文本/HTML 页面:一个是在页面加载时,另一个是在一段时间后已过。

每次单击一个按钮时,每个按钮都能正常工作。如果我在第一个请求完成之前单击按钮 2,然后单击按钮 3,则更新仍按预期工作。

如果我在第一个请求完成之前单击按钮 1,然后单击按钮 2,TextArea1 和 TextArea2 会收到正确的值;但是,onreadystatechange 事件调用同时发生,即第一个响应迟到,仅在第二个响应到达时处理。

示例代码

网站

<!DOCTYPE html>
<html>
<head>
<script>
function loadXMLDoc(url,target)
{
var xmlhttp;
xmlhttp=new XMLHttpRequest();

xmlhttp.onreadystatechange=function()
  {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
    document.getElementById(target).value=xmlhttp.responseText;
    }
  }
xmlhttp.open("POST",url,true);
xmlhttp.send();
}
</script>
</head>

<body>
<form>

<input type="button" value="Button 1" onClick="loadXMLDoc('slowtime.php','TextArea1')"/>
<input type="button" value="Button 2" onClick="loadXMLDoc('slowtime.php','TextArea2')"/>
<input type="button" value="Button 3" onClick="loadXMLDoc('fasttime.php','TextArea3')"/>

<div><textarea id="TextArea1"></textarea></div>
<div><textarea id="TextArea2"></textarea></div>
<div><textarea id="TextArea3"></textarea></div>

</form>
</body>
</html>

PHP 代码 (slowtime.php)

<?php
     echo date('h:i:s') . "\n";
     sleep(5);
     echo date('h:i:s') . "\n";
?>

问题[修订]

浏览器如何管理XMLHttpRequest 对象?按下按钮 2 和 3 表示每次按下都会实例化一个新对象,并且每个按钮都有独立的事件处理程序。如果对象存活超过初始函数调用(因为它们的事件处理程序存活)它们何时从内存中清除/销毁?

如果XMLHttpRequests 是单独的对象,那么向同一个 URL 发送第二个请求会如何影响第一个请求的响应时间?这可能是服务器端问题吗?

【问题讨论】:

  • 在您的xmlhttp.onreadystatechange 函数中,您是否应该使用this.responseText 而不是xmlhttp.responseText?
  • @JoshuaD.Boyd 这不应该做任何其他事情,因为xmlhttp 变量位于loadXMLDoc 内的本地范围内。
  • 在onreadystatechange 函数中将所有对xmlhttp 的引用更改为this 也有效,并且也会产生相同的行为
  • @nicholas 你能包含 slowrand.php 和 fastrand.php 的源代码吗?
  • @seliopou:你让我发现了服务器端代码的一个主要问题。对于诊断,slowrand 正在打开并写入文件。第二个 slowrand 调用试图打开一个锁定的文件,因此退出错误 - 长话短说,使用不同的 php 代码来编写时间戳,我得到不同的结果。请求没有被合并,但是它们的时间被搞砸了。

标签: javascript html ajax xmlhttprequest


【解决方案1】:

除非在对象上显式调用 delete,否则 XMLHttpRequest 的上下文永远不会被删除。在这种情况下:xmlhttp。如果您希望您的应用程序运行精简和干净,您真的应该以某种方式跟踪该 var 并清理它。 Javascript 最初是为网页设计的,因此它往往会让事情变得疯狂,除非你自己阻止它。

否则,一旦对象不再被任何其他函数使用或有任何剩余的回调,浏览器的垃圾收集器可能会清除该对象。

至于您对同时发生的事件的问题,我自己无法重现该问题,这确实让我相信您的 php 配置有问题。您的服务器是否可能不允许同时运行多个脚本?

这是您在我的服务器上的示例,有一些细微的变化: http://www.seijinohki.net/test.php

【讨论】:

  • 感谢您在不同的测试服务器上发布代码。当我在 Chrome 或 Safari 中测试您的网站时,我得到的结果与上面的 rambo 相同——两个文本区域的值相同。同时,Firefox、IE9 和 Silk 没有。您的页面在 Maxthon 移动浏览器中根本无法运行。
  • 很久之后,我不接受这个作为答案,因为它直接解决了请求的上下文。一个有趣的讨论,并且至少在目前表明,Web 开发/浏览器/等在执行脚本的方式上仍然没有统一..
【解决方案2】:

这是一个浏览器问题。

  • Chrome 23&26 的行为是这样的。
  • Opera 12 没有
  • IE 9 没有
  • Firefox 17 没有

如果您将网址设为唯一,例如 slowtime.php?1 和 slowtime.php?2,则 chrome 将不再以这种方式运行。

btw- 在我的测试 chrome 中使用相同的值更新两个文本区域 - 来自第一个请求的值。并且它们都在第一个请求完成时更新,而不是在第二个请求完成时更新。这肯定是一个错误,因为它完全是错误的。我通过网络服务器日志验证了第二个请求永远不会被发送。

【讨论】:

  • 当我在 kokorohakai 的服务器上使用 Chrome 或 Safari 进行测试时,我看到了相同的结果 - 两个文本区域获得相同的值并与第一个请求一起计时。同时在我的测试服务器(localhost)上,我得到两个不同的值,与第二个计时。这让我相信答案确实非常复杂,并且基于浏览器和服务器的行为。
  • @nicholas 您的本地服务器日志是否指示两个请求?尽管如此,chrome 在我的测试中只发送了一个请求这一事实表明它存在错误(或奇怪的功能)。
猜你喜欢
  • 2012-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-02
  • 2011-06-02
  • 2016-05-20
  • 2012-04-24
  • 2014-02-07
相关资源
最近更新 更多