5

全て、

私はHeadFirstAjaxの本を使ってAjaxを勉強しています。最初の章では、少し簡略化したコード例を示しています。alert何が起こっているのかを理解するためにたくさん追加しました。コードは次のとおりです。

HTML + Ajax(index.php):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Rob's Rock 'n' Roll Memorabilia</title>
<link rel="stylesheet" href="css/default.css" />
<script>
  function createRequest() {
    try {
      request = new XMLHttpRequest();
    } catch (tryMS) {
      try {
        request = new ActiveXObject("Msxml2.XMLHTTP");
      } catch (otherMS) {
        try {
          request = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (failed) {
          request = null;
        }
      }
    }
  return request;
}

function getDetails(img){
  var title = img.title;
  alert("getDetails1");
  request = createRequest();
  alert("getDetails2");
  if (request == null) {
    alert("Unable to create request");
    return;
  }
  var url= "getDetails.php?ImageID=" + escape(title);
  alert("getDetails3");
  request.open("GET", url, true);
  alert("getDetails4");
  request.onreadystatechange = displayDetails;
  alert("getDetails5");
  request.send(null);
  alert("getDetails6");
}

function displayDetails() {
  alert("displayDetails1");
  if (request.readyState == 4) {
    alert("Request.readyState is 4");
    if (request.status == 200) {
      alert("Request.status is 200");
      detailDiv = document.getElementById("description");
      alert("displayDetails2");
      detailDiv.innerHTML = request.responseText;
      alert("displayDetails3");
    }else{
      alert("Request.status not 200");
      return;
    }
  }else{
    alert("Request.readystate not 4");
    return;
  }
}
</script>  
</head>
<body>
  <div id="wrapper">
    <div id="thumbnailPane">  
      <img src="images/SISL_Avatar2.JPG"
           title="SISL" id="SISL" onclick="getNextImage()" />  
      <img src="images/itemGuitar.jpg" width="301" height="105" alt="guitar" 
           title="itemGuitar" id="itemGuitar" onclick="getDetails(this)"/>
      <img src="images/itemShades.jpg" alt="sunglasses" width="301" height="88" 
           title="itemShades" id="itemShades" onclick="getDetails(this)" />
      <img src="images/itemCowbell.jpg" alt="cowbell" width="301" height="126" 
           title="itemCowbell" id="itemCowbell" onclick="getDetails(this)" />
      <img src="images/itemHat.jpg" alt="hat" width="300" height="152" 
           title="itemHat" id="itemHat" onclick="getDetails(this)" />
    </div>

    <div id="detailsPane">
      <img src="images/blank-detail.jpg" width="346" height="153" id="itemDetail" />
      <div id="description"></div>
    </div>

  </div>
</body>
</html>

<?php    
$details = array (
    'itemGuitar'    =>  "<p>Pete Townshend once played this guitar while his own axe was in the shop having bits of drumkit removed from it.</p>",
    'itemShades'    =>  "<p>Yoko Ono's sunglasses. While perhaps not valued much by Beatles fans, this pair is rumored to have been licked by John Lennon.</p>",
    'itemCowbell'   =>  "<p>Remember the famous \"more cowbell\" skit from Saturday Night Live? Well, this is the actual cowbell.</p>",
    'itemHat'       =>  "<p>Michael Jackson's hat, as worn in the \"Billie Jean\" video. Not really rock memorabilia, but it smells better than Slash's tophat.</p>"
);    
if (isset($_REQUEST['ImageID'])){echo $details[$_REQUEST['ImageID']];}
?>

Ajax(getDetails.php)によって呼び出されるURLは次のとおりです。

<?php

$details = array (
    'itemGuitar'    =>  "<p>Pete Townshend once played this guitar while his own axe was in the shop having bits of drumkit removed from it.</p>",
    'itemShades'    =>  "<p>Yoko Ono's sunglasses. While perhaps not valued much by Beatles fans, this pair is rumored to have been licked by John Lennon.</p>",
    'itemCowbell'   =>  "<p>Remember the famous \"more cowbell\" skit from Saturday Night Live? Well, this is the actual cowbell.</p>",
    'itemHat'       =>  "<p>Michael Jackson's hat, as worn in the \"Billie Jean\" video. Not really rock memorabilia, but it smells better than Slash's tophat.</p>"
);
echo $details[$_REQUEST['ImageID']];
?>

displayDetails質問:関数がreadystate 4で2回実行されるのはなぜですか?

上記を実行すると、コードはdisplayDetails()関数を2回実行しているように見えます。最初にdisplayDetails1、関数に入ったというアラートシグナリングを受け取ります。readyState次に、4ではない、次に4ではない、4である( )に関連するアラートを受け取りRequest.readyState is 4ます。次に、ステータスアラートはステータスが200であることを通知します。これまでのところ、予期しないことは何もありません。

その後、私は何か奇妙なことになります。 アラートが表示されたらdisplayDetails2、機能に応じてページが変更され、アラートが表示されますdisplayDetails3。次に、関数を終了する予定です。代わりに、関数全体が2回実行されたかのようにdisplayDetails1Request.readyState is 42回目!Request.status is 200、、、displayDetails2およびアラートが再度表示されます。displayDetails3何故ですか?

PS:
1)第2ラウンドの後、getDetails6私は期待するアラートを受け取ります。
2)ページは正常に機能します。ユーザーの観点からは、アラートが無効になっている場合でも異常はありません。3)私はWampServer、WinXPマシンでローカルに開発しています(私は知っています...)。
4)追加した場合:

function alert(msg) {
  console.log(msg);
}

私のスクリプトに、ログは1つだけを登録しますreadyState is 4...

解像度

私は3つのテストを行いました:
1-アラートのみで、2つのreadyState is 4アラートを受け取ります。
2-アラートをログに記録すると、ログには1つのreadyState is 4アラートのみが表示されます。3-(この関数
を使用して)アラートポップアップをログに記録して表示すると、 2つのアラートが表示されます(ログにはそれが示されます)。readyState is 4

これについての私の見解は、スクリプトの実行遅延を引き起こし、関数を効果的に2回実行させるのは、アラート自体であるということです。

4

2 に答える 2

7

javascriptalertがUIスレッドをブロックしています。おそらく、ブラウザがAJAXリクエストの読み込みを完了するのに十分な時間です。アラートが出るまでチェックしないので、チェックするrequest.readyState前にブラウザで更新できます。

イベントハンドラーを変更してみてください。

function displayDetails() {
  var rs = request.readyState;
  alert("displayDetails1");
  if (rs == 4) {
    alert("Request.readyState is 4");
    //rest of code...

「Request.readyStateis4」のアラートが1つだけ表示されます

于 2013-02-05T20:23:37.227 に答える
5

イベントは、onreadystatechangeリクエストが完了した後にのみトリガーされるわけではありません。XMLHttpRequestには5つの状態が定義されています。

  • 0初期化されていない初期値。
  • 1 Open open()メソッドが正常に呼び出されました。
  • 2送信済みUAはリクエストを正常に完了しましたが、データはまだ受信されていません。
  • 3メッセージ本文(存在する場合)を受信する直前に受信します。すべてのHTTPヘッダーが受信されました。
  • 4ロード済み

通常、AJAXアプリケーションを開発するときは、リクエストが終了したことを意味するため、状態4-ロードのみに関心がありますが、観察できる他の状態があります。

したがって、イベントハンドラーへの2回目の呼び出しについて心配する必要はありません。これは正常な動作です。これは、リクエストが作業中に内部状態を変更したことを意味します。

その状態に興味がある場合は、すべての状態をjavascriptコンソールに記録して、何が起こっているかを確認することをお勧めします。また、大きなデータをロードするときに、これをtippテストします。複数の3つの受信状態が表示される可能性があります。


更新、多分私はあなたの質問が間違っていることを理解しています(しかしあなたのコードは理解していません;)..あなたはコメントであなたが2回準備完了状態4を見ると言いました。

次に、JavaScriptセクションに次の関数を追加しました。

function alert(msg) {
    console.log(msg);
}

これにより、すべてのアラートがjavascriptデバッグコンソールにリダイレクトされます。次の出力が得られました。

ここに画像の説明を入力してください

準備完了状態4が1回だけ表示されます。alert()が多すぎるため、勝手に配線されたようです;)


Update2:コメントと@thanksで述べたように、これも指摘してくれたJeff-Meadows:alert()[OK]ボタンを押さない限り、関数はjavascriptスレッドをブロックすることに注意してください。非同期XHRリクエストは別のブラウザスレッドによって処理されるため、JavaScriptがアラートメッセージをブロックしている間、XHRはロードを継続します。これにより、望ましくない副作用が発生する可能性があり、alert()のデバッグ目的での価値が低下することがわかります。

于 2013-02-05T19:09:03.267 に答える