为什么我的AJAX函数多次调用回调?

ahu*_*uth 7 javascript ajax

我做了一个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));
Run Code Online (Sandbox Code Playgroud)

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

// 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));
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我正在尝试将依赖项作为局部变量/名称空间引入.当它运行时,它会弹出警报框3次.

我不确定这个问题是由于ajax函数本身还是整体架构(或两者),所以我很感激评论或想法.

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

编辑: 这是整个HTML文件,所以你可以看到我包含的顺序<script>.

<!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>
Run Code Online (Sandbox Code Playgroud)

编辑2:

我的例子中有一个拼写错误,并且发生了变化

(function (window, document, bigmap, ajax) {
Run Code Online (Sandbox Code Playgroud)

(function (window, document, ajax) {
Run Code Online (Sandbox Code Playgroud)

编辑3:

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

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

当我逐步浏览Google Chrome中的代码时,会调用三次回调,并且控制台会记录:

readyState: 4
readyState: 4
readyState: 4
Run Code Online (Sandbox Code Playgroud)

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

readyState: 2
readyState: 3
readyState: 3
readyState: 4
Run Code Online (Sandbox Code Playgroud)

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

解决了:

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

因此,状态更换3次,但执行已被破发点的延迟,因此所有3个onreadystatechange功能看到一个由4目前的状态,而不是什么状态在变化实际发生.

外卖是onreadystatechange变化不存储该状态.相反,它会readyState 在执行时读取,即使程序被中断,状态也会在平均时间内再次发生变化.

因此,AJAX需要不同于使用完全同步代码的调试技术......但您可能已经知道了.

感谢所有在这里帮忙的人.

Eli*_*gem 9

readyState有4种不同的状态:

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

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

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

只是硬编码他们,而不是使用不可靠的变量(名称doneok看似危险的我).

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

return {post : function()
{
};
Run Code Online (Sandbox Code Playgroud)

或者作为一个匿名.功能,分配给变量post:

var post = function(){};
Run Code Online (Sandbox Code Playgroud)

各种引擎通过功能,您声明它们的方式,提升它们来做各种事情.此外post,如果你问我感觉不对的函数名称...我想尝试使用的名称,不看像他们可能会被保留...

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

XHR.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
Run Code Online (Sandbox Code Playgroud)

这可能只是造成问题的原因(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
});
Run Code Online (Sandbox Code Playgroud)