8

ajax post関数を作成しましたが、これを1回呼び出すと、渡されるコールバック関数が3回呼び出されることになります。 コールバックが複数回呼び出されるのはなぜですか?

クロージャを使用して1つのグローバル変数の下で同様の機能をラップする「モジュール」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);
    }
};

Google Chromeでコードをステップ実行すると、コールバックが3回呼び出され、コンソールは次のログを記録します。

readyState: 4
readyState: 4
readyState: 4

ただし、ページを通常どおり実行し、ステップスルーしない場合、関数は期待どおりに機能し、コールバックを1回だけ実行します。この場合、コンソールは次のログを記録します。

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

だから今私の質問は、コードをステップスルーするときにコールバックが複数回呼び出されるのはなぜですか?

解決済み:

この質問をしたとき、デバッグ中にコードをステップ実行しているときにのみ発生していることに気づきませんでした。

つまり、状態は3回変化しましたが、実行がブレークポイントによって遅延しているため、3つの関数すべてで、実際に変化が発生したときの状態ではonreadystatechangeなく、現在の状態4が表示されます。

要点は、onreadystatechange変更はその状態が何であるかを保存しないということです。readyState 代わりに、プログラムが中断された場合でも、実行時にを読み取り、その間に状態が再び変化します。

したがって、AJAXには、完全同期コードで使用するものとは異なるデバッグ手法が必要です...しかし、おそらくすでにそれを知っているでしょう。

ここで助けてくれたすべての人に感謝します。

4

3 に答える 3

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、私に言わせれば、関数名として正しく感じられません...予約されているように見えない名前を使用しようと思います...

X-Requested-Withまた、XHRのヘッダーを明示的に設定していません。

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関数を呼び出す場合、少なくとも2回postを呼び出しませんか。1回はオブジェクトのインスタンス化で、次はメソッド呼び出しです。

于 2012-11-08T16:55:58.660 に答える
0

私はajaxを使用するのはまったく新しいですが、解決しようとしているのと同じ問題があります。私はw3choolsのajaxについて読んでいます。this.readystate状態をチェックするときに、を使用するのでthis.status はなく、を使用することに気づきましたobject.readystate。どういうわけか、object.readystateで3回起動し、。で正常に動作すると思いますthis.readystate。明日チェックしますが、それが問題かもしれないと思います。

于 2016-11-20T19:49:05.420 に答える