[Work/Class/ES2015で動的Webアプリ/ES2015Basic]

ES2015の基本 - PromiseとXMLHttpRequestを使ったAjaxとfetch / 2017-10-18 (水)

XMLHttpRequestクラスとそのインスタンス

簡単に言えば,インタラクティブに他のページや画像などを持ってきて,今のページに表示させるためのクラスである.

Promiseクラスのオブジェクトを生成するように設計してやると,「読み込み終わって,結果が正しい時に,次のコードを実行する」という処理ができる.

Cross-Originポリシーの関係で,XMLHttpRequestクラスのインスタンスは,そのJavaScriptファイルが置いてあるドメインからしかAjaxできない.(正確には色々やればできるが面倒臭い)

コード例

htmlを取得して,その結果をテキストとしてdivに表示する.

実行ページ

Cross-Originポリシーの関係で,XMLHttpRequestクラスのオブジェクトは,そのJavaScriptファイルが置いてあるドメインからしかAjaxできない.(できるが面倒臭い)

<!DOCTYPE html>
<!-- PromiseAjaxWithClass.html -->
<html lang="ja">
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta charset="utf-8">
    <title>Promiseを使ってAjax</title>
    
    <script type="text/javascript" src="./PromiseAjaxWithClass.js">
    </script>
  </head>
  <body>
    <p>取得したいHTMLのURLを記入</p>
    <form>
      <input type="text" name="target_url" value="http://cad.lolipop.jp/" />
      <input type="button" name="send_button" value="取得" onclick="getHtml(this.form.elements['target_url'].value)" />
    </form>
    <div id="display_iframe">
      ここに取得してきたものが表示されます.
    </div>
  </body>
</html>
// PromiseAjaxWithClass.js
'use strict';
class MyAjax{
    constructor(targetUrl){
	this.targetUrl = targetUrl;
	this.gottenHtmlPage = '';
    }

    setTargetUrl(targetUrl){
	this.targetUrl = targetUrl;
    }

    setDisplayingDivId(divId){
	this.divId = divId;
    }

    // AjaxによるHTMLページの取得を実行する関数 Promiseを返す
    startHttpRequest(){
	return new Promise((resolve, reject) => {
	    let xmlHttpRequest = new XMLHttpRequest();
	    //open(HTTPメソッド, URL, 非同期モードかどうか, ユーザ名, パスワード)
	    xmlHttpRequest.open('GET', this.targetUrl, true);
	    xmlHttpRequest.onload = () => {
		if(xmlHttpRequest.status >= 200 && 
		   xmlHttpRequest.status < 300){
		    resolve(xmlHttpRequest.responseText);
		}
		else{
		    reject(xmlHttpRequest.status);
		}
	    };
	    xmlHttpRequest.onerror = () => {
		reject(xmlHttpRequest.status);
	    };
	    //設定が終わった後にsend(null)を実行すると取得が始まる.
	    xmlHttpRequest.send(null);
	});
    }

    // AjaxによるHTMLページの取得が完了した時に呼び出すコールバック関数
    whenFinishSuceed(result){
	document.getElementById('display_iframe').innerText = result;
    }

    whenFinishFailed(err){
	document.getElementById('display_iframe').innerHTML = 
	    '<p>' + 'Faild to get WebPage. Error code is: ' + err + '</p>';
    }
}

window.getHtml = (targetUrl) => {
    window.myAjax.setTargetUrl(targetUrl);
    window.myAjax.startHttpRequest()
	.then(window.myAjax.whenFinishSuceed)
	.catch(window.myAjax.whenFinishFailed);
};

window.addEventListener('load', () => {
    window.myAjax = new MyAjax('http://cad.lolipop.jp/');
    window.myAjax.setDisplayingDivId('display_iframe');
    window.myAjax.startHttpRequest()
	.then(window.myAjax.whenFinishSuceed)
	.catch(window.myAjax.whenFinishFailed);
});

fetch API

とまぁ,自分で実装すると面倒臭いことこの上ないのだが,Promiseのインスタンス(オブジェクト)を返す全く同じ機能がfetch関数として既に標準ライブラリとして実装されており,Chromeでは問題なくXMLHttpRequestクラスの代わりとして使用できる.

おまけに,Cross-Originポリシーも(サーバが対応していれば)一行設定を書いてやるだけで無視することができる.

コード例

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title>Fetch API Test</title>
    <script type="text/javascript">
      window.addEventListener('load',  () => {
	  fetch('http://sfdn-w1.sd.tmu.ac.jp/~daichi/', {
	      method: 'GET',
	      mode: 'cors' //Cross-Originポリシーを無視する
	  }).then((response) => {
	      return response.text()
	  }).then((text) => {
	      document.getElementById('for_display').innerText = text;
	  }).catch((error) => {
	      console.log(error);
	  });
      });
    </script>
  </head>
  <body>
    <div id="for_display">
    </div>
  </body>
</html>