8

我制作了一个 ajax post 函数,当我调用它一次时,传递给它的回调函数最终被调用了 3 次。 为什么多次调用回调?

我正在尝试使用一种“模块”javascript 模式,该模式使用闭包将类似的功能包装在一个全局变量下。我的 ajax 模块是它自己的文件,看起来像这样:

var ajax = (function (XMLHttpRequest) {
    "use strict";

    var done = 4, ok = 200;

    function post(url, parameters, callback) {

        var XHR = new XMLHttpRequest();

        if (parameters === false || parameters === null || parameters === undefined) {
            parameters = "";
        }

        XHR.open("post", url, true);
        XHR.setRequestHeader("content-type", "application/x-www-form-urlencoded");
        XHR.onreadystatechange = function () {
            if (XHR.readyState === done && XHR.status === ok) {
                callback(XHR.responseText);
            }
        };
        XHR.send(parameters);
    }

    // Return the function/variable names available outside of the module.
    // Right now, all I have is the ajax post function.
    return {
        post: post
    };

}(parent.XMLHttpRequest));

主应用程序也是它自己的文件。例如,它看起来像这样:

// Start point for program execution.

(function (window, document, ajax) {
    "use strict";

    ajax.post("php/paths.php", null, function () { window.alert("1"); });

}(this, this.document, parent.ajax));

如您所见,我试图将依赖项作为局部变量/命名空间引入。当它运行时,它会弹出警告框 3 次。

我不确定这个问题是由于 ajax 函数本身还是整体架构(或两者兼而有之)造成的,所以我很感激对任何一个的评论或想法。

我试过从匿名函数中解开程序的主要部分,但这没有帮助。提前致谢!

编辑: 这是整个 HTML 文件,因此您可以看到我包含<script>'s 的顺序。

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <meta http-equiv="expires" conent="0" />
    <title>Mapalicious</title>
    <link href="css/main.css" type="text/css" rel="stylesheet" />
    <script src="js/raphael.js"></script>
</head>
<body>
    <div id="map"></div>
    <script src="js/promise.js"></script>
    <script src="js/bigmap.js"></script>
    <script src="js/ajax.js"></script>
    <script src="js/init.js"></script>
</body>
</html>

编辑2:

我在我的例子中有一个错字,并改变了

(function (window, document, bigmap, ajax) {

(function (window, document, ajax) {

编辑 3:

我已经更改了onreadystatechange将就绪状态记录到控制台的功能:

XHR.onreadystatechange = function () {
    console.log("readyState: " + XHR.readyState);
    if (XHR.readyState === done && XHR.status === ok) {
        callback(XHR.responseText);
    }
};

当我在谷歌浏览器中单步执行代码时,回调被调用了 3 次,控制台记录:

readyState: 4
readyState: 4
readyState: 4

但是,当我正常运行页面并且不单步执行时,该函数按预期工作并且只运行一次回调。在这种情况下,控制台会记录:

readyState: 2
readyState: 3
readyState: 3
readyState: 4

所以现在我的问题是,为什么在单步执行代码时会多次调用回调?

解决了:

当我问这个问题时,我没有意识到只有在调试时单步执行代码时才会发生这种情况

所以,状态改变了 3 次,但是执行被断点延迟了,所以所有 3 个onreadystatechange函数都看到了 4 的当前状态,而不是实际发生变化时的状态。

要点是onreadystatechange更改不会存储该状态是什么。readyState 相反,它在执行时读取,即使程序被中断,同时状态再次发生变化。

因此,AJAX 需要与使用完全同步代码不同的调试技术……但您可能已经知道这一点。

感谢所有在这里提供帮助的人。

4

3 回答 3

9

有 4 个不同的readyState状态:

0 - 未初始化请求
1 - 连接到服务器
2 - 收到请求
3 - 正在处理
4 - 完成,收到响应

这些更改中的每一个都将调用onreadystatechange处理程序。这就是为什么大多数这些函数看起来像这样:

xhr.onreadystatechange = function()
{
    if (this.readyState === 4 && this.status === 200)
    {
        //do stuff with this.responseText
    }
}

只需对它们进行硬编码,而不是使用狡猾的变量(这些名称对我done来说ok似乎很危险)。

除此之外,尝试post直接在返回的对象中声明函数:

return {post : function()
{
};

或作为匿名。函数,分配给变量post

var post = function(){};

各种引擎用函数做各种各样的事情,你声明它们的方式,提升它们,其中之一。post如果您问我,作为函数名称也感觉不正确...我会尝试使用看起来不像保留名称...

此外,您没有明确设置 XHR 的X-Requested-With标头:

XHR.setRequestHeader('X-Requested-With', 'XMLHttpRequest');

这可能只是导致问题的原因(HTTP1.1 和传输编码分块?)

callback(XHR.responseText);为了使调试更容易,请尝试通过更改为每次显示警报时记录 XHR 对象callback.apply(this,[this.responseText]);,尽管该参数是多余的。然后,更改ajax.post("php/paths.php", null, function () { window.alert("1"); });为:

ajax.post("php/paths.php", null,
function (response)
{
     console.log(this.readyState);//or alert the readyState
     window.alert(response);//check the response itself, for undefined/valid responses
});
于 2012-11-08T17:01:50.557 回答
0

在我看来,您的 ajax 对象正在返回对 post 函数的调用。如果是这样,并且您在 ajax 变量上调用 post 函数,它不会调用 post 至少两次:一次在对象实例化时,下一次在方法调用上?

于 2012-11-08T16:55:58.660 回答
0

我在使用 ajax 方面很新,但我遇到了同样的问题,我正在尝试解决。我一直在阅读 w3chools 中有关 ajax 的信息。我注意到,当检查状态时,他们使用this.readystatethis.status 不是. object.readystate我认为出于某种原因,它会在 e 上触发 3 次object.readystat并且与this.readystate. 我明天会检查它,但我认为这可能是问题所在。

于 2016-11-20T19:49:05.420 回答