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

时间:2012-11-08 16:46:14

标签: 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));

主应用程序也是它自己的文件。作为一个例子,它看起来像这样:

// 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>的订单。

<!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);
    }
};

当我浏览谷歌浏览器中的代码时,回调被调用三次,控制台记录:

readyState: 4
readyState: 4
readyState: 4

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

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

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

解决:

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

所以,状态改变了3次,但执行时间被延迟了,因此所有3个onreadystatechange函数都看到当前状态为4,而不是状态实际发生变更时,

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

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

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

3 个答案:

答案 0 :(得分:9)

readyState有4种不同的状态:

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

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

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

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

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

return {post : function()
{
};

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

var post = function(){};

各种引擎通过功能,你声明它们的方式,提升它们来做各种事情。如果你问我,post作为一个函数名称感觉不对...我会尝试使用看起来不像可能保留的名字... < / p>

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

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

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

为了使调试更容易,请尝试通过将callback(XHR.responseText);更改为callback.apply(this,[this.responseText]);来每次显示警报时记录XHR对象,尽管参数是多余的。然后,将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
});

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我在使用ajax方面相当新,但我遇到的问题与我要解决的问题相同。我一直在读w3学校的ajax。我注意到,当状态被选中时,他们使用this.readystatethis.status 而不是 object.readystate。我认为由于某种原因,它会在object.readystat e上触发三次并且与this.readystate一起正常工作。我明天会检查,但我认为这可能是问题。