3

「PHP、MySQL、JavaScriptの学習-O'Reilly」で非常に基本的なAJAXプログラミングを行っています。JavaでテキストまたはAJAXを使用したページを取得する非常に基本的なプログラムがいくつかあります。私はW3Schools.comサイトを使用して、AJAXでXML形式のドキュメントを取得する方法について詳しく学ぼうとしています。私が学んでいることに関連する2つの質問があります。

http://www.w3schools.com/dom/dom_loadxmldoc.aspのコードを使用すると、以下のスニペットを含むXMLドキュメントを返すことができます。

function loadXMLDoc(dname)
{
if (window.XMLHttpRequest)
  {
  xhttp=new XMLHttpRequest();
  }
else
  {
  xhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
xhttp.open("GET",dname,false);
xhttp.send();
return xhttp.responseXML;
}

//called this way
xmlDoc=loadXMLDoc("books.xml");

ただし、これを機能させるには、非同期をfalseに設定する必要があります。asyncをtrueに設定すると、nullが返されます。だから私の最初の質問は、これがXMLドキュメントを返すために非同期がfalseでなければならないのはなぜですか?

2番目の質問ですが、本のコードとWebサイトのコードを組み合わせようとすると、スニペットは次のようになります。

<body>API Call output
<div id='output'>will be here</div>
<script>
out = ""
xmlDoc = getResponse()
users = xmlDoc.getElementsByTagName('username')
for (count = 0; count < users.length ; count++)
{
    out += "Username: " + users[count].childNodes[0].nodeValue + '<br />'
}
document.getElementById('output').innerHTML = out

function ajaxRequest()
{
    try //good browser
    {
        var request = new XMLHttpRequest()
    }
    catch(e1)
    {
        try // IE6+
        {
            request = new ActiveXObject("Msxml2.XMLHTTP")
        }
        catch(e2)
        {
            request = false
        }
    }//end catch(e1)
    return request
}

function getResponse()
{
    params = "apikey=test"
    request = new ajaxRequest()
    request.open("POST", "processapi.php", true)
    request.setRequestHeader("Content-type",
        "application/x-www-form-urlencoded")
    request.setRequestHeader("Content-length", params.length)
    request.setRequestHeader("Connection", "close")
    request.onreadystatechange = function()
    {
        if (this.readyState == 4)
        {
            if (this.status == 200)
            {
                if (this.responseXML != null)
                {
                    return this.responseXML
                }
                else alert("Ajax error: No data received")
            }
            else alert( "Ajax error: " + this.statusText)
        }
    }

    request.send(params)
}
</script>
</body>

「TypeError:xmlDocisundefined」というエラーが表示されます。asyncをtrueまたはfalseに設定した関数getResponse()では機能しませんが、xmlDocisundefinedエラーが発生します。xmlDocは、loadXMLDoc()の戻り値に設定される前に、最初の例(w3schools.comから)の他の場所で定義されておらず、正常に機能します。ajaxRequest()は本の外にあり、getResponse()のほとんどすべてが本の外にありますが、私はそれをgetResponse()関数に入れました。processapi.phpは、このスクリプトから呼び出されたときにXMLドキュメントをエコーするだけです。

最初の例で非同期が機能しないのはなぜですか?また、2番目の例でxmlDocが定義されていないのはなぜですか?どんな助けでも大歓迎です。

4

2 に答える 2

0

両方の質問に対する答えは、非同期性の性質にあります。でasyncあるtrue場合、これは次を返しますnull

xhttp.open("GET",dname,false);
xhttp.send();
return xhttp.responseXML;

return...ステートメントが発生するまでに HTTP 要求が完了していないため、xhttp.responseXMLまだデフォルト値 ( null) のままです。HTTP 要求は、そのコードの流れから後で完了します (非同期的に — 文字通り、同期ではありません)。

あなたのgetResponse関数はまったく値を返しません。割り当てた匿名のコールバック関数は値をonreadystatechange返しますが、それは の戻り値にはまったく影響しませんgetResponse

クライアント側 Web プログラミングの重要な側面の 1 つは、環境の非同期でイベント駆動型の性質を取り入れることです。XHR リクエストで を設定asyncするユースケースは事実上ありません。false代わりに、コールバックを使用することに慣れてください。たとえば、getResponse関数は次のようになります。

// ***CHANGE*** -----v--- Accept a callback
function getResponse(callback)
{
    params = "apikey=test"
    request = new ajaxRequest()
    request.open("POST", "processapi.php", true)
    request.setRequestHeader("Content-type",
        "application/x-www-form-urlencoded")
    request.setRequestHeader("Content-length", params.length)
    request.setRequestHeader("Connection", "close")
    request.onreadystatechange = function()
    {
        if (this.readyState == 4)
        {
            if (this.status == 200)
            {
                if (this.responseXML != null)
                {
                    // ***CHANGE*** Trigger the callback with the response
                    callback(this.responseXML);
                }
                else alert("Ajax error: No data received")
            }
            else alert( "Ajax error: " + this.statusText)
        }
    }

    request.send(params)
}

次に、これの代わりに:

out = ""
xmlDoc = getResponse()
users = xmlDoc.getElementsByTagName('username')
for (count = 0; count < users.length ; count++)
{
    out += "Username: " + users[count].childNodes[0].nodeValue + '<br />'
}
document.getElementById('output').innerHTML = out

あなたはこれをします:

getResponse(function(xmlDoc) {
    out = ""
    users = xmlDoc.getElementsByTagName('username')
    for (count = 0; count < users.length ; count++)
    {
        out += "Username: " + users[count].childNodes[0].nodeValue + '<br />'
    }
    document.getElementById('output').innerHTML = out
});

応答に依存するすべてのコードを関数に移動し、その関数を に渡したことに注意してくださいgetResponsegetResponseデータがあるときに呼び出します。リクエスト/レスポンス、イベントドリブン、非同期など、呼び方は何でも構いませんが、これは早い段階で取り入れるべき重要なことです。:-)


補足: あなたのコードはThe Horror of Implicit Globals の餌食になっています。グローバル シンボルの作成を避けるために、すべての変数を宣言し、すべてのコードをスコープ関数でラップすることを強くお勧めします (ブラウザーのグローバル名前空間は既に混雑しています)。

于 2012-12-01T11:12:55.270 に答える
0

getResponseは非同期 XHR リクエストを実行しているため、結果の準備が整う前に関数が返されます。代わりに、コールバック アプローチを使用する必要があります。

コールバック パラメータを受け入れるように関数宣言を変更します。

function getResponse(callback) {

次に、関数本体のこの部分を変更します

if (this.responseXML != null)
{
    return this.responseXML; // WRONG
}

XML の受信時にコールバックを呼び出すようにします。

if (this.responseXML != null)
{
    callback(this.responseXML); // GOOD
}

getResponse次に、次のように呼び出します。

getResponse(function(xmlDoc){
   // do something with xmlDoc
})
于 2012-12-01T11:15:47.293 に答える