Sync(同期)とAsync(非同期)



前回は、Ajax関連のツールを使い、XMLファイルを読み込んで利用する方法を紹介しました。今回は、少し基本に戻ってAjaxの動作のSync(同期)とAsync(非同期)について解説します。

「Ajax」ということばの由来や、この単語が、Asynchronous JavaScript + XML(非同期なJavaScriptとXML)の略(注*1)だということなどについては、「Ajaxって何?」で解説しました。今回は、この「Asynchronous(非同期)」について、調べてみます。

以下、Asynchronousという単語はAsync、反対の意味であるSynchronous(同期)は、Syncと略します。

(注*1「Aj+XML」とは言っても、AjaxにおいてXMLは必要条件ではなく、JSONやTEXTなど軽量データを利用するといったケースも増えています。そういう意味では「Aj+X」と言えるのかもしれません。)

  • 1: とりあえず、体感してみよう
    (*このサンプルは上記リンク参照)

    Ajaxのメリットとして、おそらく誰もが最初にあげるのは、「ページ遷移無しで高速に画面を書き換えられる」とか 「サーバ処理待ちをしない非同期リクエストが可能」といったユーザーインターフェイス上の利点でしょう。

    ページ遷移無しで作業ができることのメリットは、使ってみれば誰の目にも明らかですが、「サーバ処理待ちをしない非同期リクエスト」とは、どのようなものでしょうか。

    ここでは、まず、非同期リクエストと同期リクエストの体感上の違いを確認してみます。

    動作ブラウザ
    win mac linux
    n7 m1 e6 o7 o8 n7 m1 e5 s1 n7 m1 k3
    × ×


    使ったソースは、下記の通りです。

    【JavaScript側】
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <meta http-equiv="content-script-type" content="text/javascript">
    
    <!-- 暫定Ajaxライブラリを読み込む -->
    <script type    = "text/javascript" 
            charset = "utf-8"
            src     = "./jslb_ajax03.js"></script>
            
    <script language="JavaScript">
    <!--
    
    	////
    	// 受信時に起動するコールバック関数
    	//
    	// @sample onloaded(res)
    	// @param res レスポンス
    	//
    	function onloaded(res)
    	{
    	  alert( "今受信しました : " + res.responseText  )
    	}
    
    	////
    	// 送信処理用関数
    	//
    	// @sample sendData(true)
    	// @param async	非同期ならtrue 同期ならfalse
    	//
    	function sendData(async)
    	{
    	
    	  //送信
    	  sendRequest( onloaded,'','GET','./about1.php',async,true )
    	}
    
    //-->
    </script>
    
    <form name="test1">
    <b>【Sync(同期)】</b>
    <br>
      <input type    = "button"
             value   = "同期"
             onclick = "sendData(false)">
    <br><br>
    <b>【Async(非同期)】</b>
    <br>
      <input type    = "button"
             value   = "非同期"
             onclick = "sendData(true)">
    </form>
    

    【今回の暫定Ajax用ライブラリ】jslb_ajax03.js
    ////
    // XMLHttpRequestオブジェクト生成
    //
    // @sample oj=createHttpRequest()
    // @return XMLHttpRequestオブジェクト
    //
    function createHttpRequest()
    {
    	if(window.ActiveXObject){
    		 //Win e4,e5,e6用
    		try {
    		  return new ActiveXObject("Msxml2.XMLHTTP") ;
    		} catch (e) {
    		  try {
    		    return new ActiveXObject("Microsoft.XMLHTTP") ;
    		  } catch (e2) {
    		    return null ;
     		  }
     		}
    	} else if(window.XMLHttpRequest){
    		 //Win Mac Linux m1,f1,o8 Mac s1 Linux k3用
    		return new XMLHttpRequest() ;
    	} else {
    		return null ;
    	}
    }
    
    ////
    // 送信関数
    //
    // @sample sendRequest(onloaded,'&p=1','POST','./about2.php',true,true)
    // @param callback 受信時に起動する関数名
    // @param data	 送信するデータ
    // @param method "POST" or "GET"
    // @param urlリクエストするファイルのURL
    // @param async	非同期ならtrue 同期ならfalse
    // @param sload	スーパーロード trueで強制、省略またはfalseでデフォルト
    //
    function sendRequest(callback,data,method,url,async,sload)
    {
    	//XMLHttpRequestオブジェクト生成
    	var oj = createHttpRequest()
    	if( oj == null ) return null
    	
    	//強制ロードの設定
    	var sload = (!!sendRequest.arguments[5])?sload:false;
    	if(sload)url=url+"?t="+(new Date()).getTime()
    	//ブラウザ判定
    	var ua = navigator.userAgent
    	var safari	= ua.indexOf("Safari")!=-1
    	var konqueror = ua.indexOf("Konqueror")!=-1
    	var mozes	 = ((a=navigator.userAgent.split("Gecko/")[1] )
    			?a.split(" ")[0]:0) >= 20011128 
    	
    	//受信処理
    	//operaはonreadystatechangeに多重レスバグがあるのでonloadが安全
    	//Moz,FireFoxはoj.readyState==3でも受信するので通常はonloadが安全
    	//Win ieではonloadは動作しない
    	//Konquerorはonloadが不安定
    	//参考http://jsgt.guide.withabout.net/guide_jsgt/gp333/ajax/ref/test/response/responsetext/try1.php
    	if(window.opera || safari || mozes){
    		oj.onload = function () { callback(oj) }
    	} else {
    	
    		oj.onreadystatechange =function () 
    		{
    			if ( oj.readyState == 4 ){
    				callback(oj)
    			}
    		}
    		
    	}
    	
    	//エンコード
    	if(method == 'GET') {
    		url = url + encodeURI(data)
    	}
    	
    	//open メソッド
    	oj.open( method , url , async )
    	
    	if(method == 'POST') {
    		//このメソッドがWin Opera8でエラーになったので分岐
    		if(!window.opera)
    			oj.setRequestHeader('Content-Type', 
    				'application/x-www-form-urlencoded')
    	} 
    	
    	//send メソッド
    	oj.send(data)
    }
    

    【サーバー側】
    <?php
    
    	//4秒スリープ
    	sleep(4);
    	//出力する文字コードをutf-8にセットして、、、
    	mb_http_output ( 'UTF-8' );
    	//出力
    	echo " Woke up ! This is a response. " ;
    
    ?> 
    
    
    このサンプルでは、「同期」ボタンを押すと、同期モードでリクエストが送信され、「非同期」ボタンを押すと、非同期モードでリクエストが送信されます。

    サーバーでは、4秒間スリープ(停止)したあと、そのリクエストに対するレスポンスとして「 Woke up ! This is a response. 」という文字列を送出する仕掛けになっています。

    同期モードでは、リクエスト送信後、レスポンスが帰ってくるまで、ブラウザはロックされるので何もできなくなります。これに対して、非同期モードでは、リクエスト送信後、レスポンスが帰ってこなくても、すぐに次の作業にとりかかることができます。

    このサーバーとのやり取り流れについては、前々回も紹介した、Jesse James Garrett氏による 解説(和訳)の『図 2: 伝統的な Web アプリケーションにおける同期型のやりとり(上)と、Ajax アプリケーションにおける非同期型のやりとり(下)』が参考になるでしょう。

    【今回の暫定Ajax用ライブラリ】jslb_ajax03.jsの中の受信処理などに書き込まれているブラウザ分岐の根拠は、 レスポンスのタイミングについての(ブラウザごとの違いについての)調査などの結果に基づいています。

    次に、リクエスト送信後、ロックせずに動作できるサンプルとして、前回も利用したプログレスバーを組み合わせてみます。