【社内勉強会】Ajaxの基礎(2017/10/18) 

【社内勉強会】Ajaxの基礎(2017/10/18) 

# 0. はじめに

-------
## 内容

* Ajaxの基礎。`XMLHttpRequest`（ライブラリを使わずに）で理解する。


### 前提知識
* JavaScriptの基本的な構文を理解している人
 - 配列
 - オブジェクト
 - イベント
 - コールバック関数

### 注意
ここで紹介したXMLHttpRequestの使い方は、サンプル用で実務には適していません。以下の内容を考慮していません。

* エラー処理
* URLエンコード

-------
## 参考図書

![image](https://qiita-image-store.s3.amazonaws.com/0/37903/8672c64c-9a0c-7af7-17a3-294b43dab53f.png)
[『改訂新版JavaScript本格入門』技術評論社](http://gihyo.jp/book/2016/978-4-7741-8411-1)
2016年発売で、ES2015に対応。

-------
## 目次
1. `XMLHttpRequest`でAjax
2. ライブラリでAjax
3. JSONとAjax

-------
# 1. `XMLHttpRequest`でAjax

-------
## Ajaxとは

Asynchronous JavaScript + XMLの略。
>JavaScript(XMLHttpRequestオブジェクト）を利用してサーバ側と非同期通信を行い、受け取った結果をDOM経由でページに反映するしくみ

※ 『JavaScript本格入門』P389 引用
    
-------
### 従来型のWebアプリとAjaxアプリの比較した画像

![image.png](https://qiita-image-store.s3.amazonaws.com/0/37903/8f6b1af6-aee6-044a-d8d9-9f3855b861cb.png)

※[Ajax - Wikipedia](https://ja.wikipedia.org/wiki/Ajax) 引用

-------
## 従来型のWebアプリ

JSPで動作を確認する。
二乗した結果を表示する画面。

```jsp:form.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%
String strInput = request.getParameter("input");
String strOutput = "";
if (strInput != null) {
	try {
		Integer input = Integer.valueOf(strInput);
		Thread.sleep(1000);
		strOutput = String.valueOf(input * input);
	} catch(Exception e) {}
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>

<body>
<form action="/SampleWeb/form.jsp" method="POST">
	INPUT: <input name="input" type="text">
	OUTPUT: <input name="output" type="text" value="<%=strOutput%>">
	<input type="submit">
</form>
</body>
</html>
```


-------
### 従来型のWebアプリの特徴

* 結果を表示する際に、ページ全体が書き換えられる
 - 常にぺージ全体をリフレッシュする必要がある
 - トラフィック量に無駄がある 
* サーバと通信している間、クライアント側は操作できない



-------
## Ajaxアプリ

Ajax通信で結果を表示するためのServletを用意する。

```java:PowServlet.java
/**
 * クエリパラメタ"input"の値の二乗した結果を出力
 */
@WebServlet("/pow")
public class PowServlet extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String strInput = request.getParameter("input");
		String strOutput = "";
		if (strInput != null) {
			try {
				Integer input = Integer.valueOf(strInput);
				//数秒待つ
				Thread.sleep(1000);
				strOutput = String.valueOf(input * input);
			} catch(Exception e) {}
		}
        PrintWriter out = response.getWriter();
        out.println(strOutput);
	}
}
```


-------
### XMLHttpRequestで非同期通信を実施

```javascript:sample.js
/**
 * Calculateボタンを押したときの処理
 */
function calculate() {
	const xhr = new XMLHttpRequest();
	//リクエストが成功したときのイベントを設定
	xhr.addEventListener("load", function() {
		const output = xhr.responseText; //二乗の結果
		//テキストボックスに表示
		document.getElementById("output").value = output;
	} ,false);

	const url = "/SampleWeb/pow?input=" + document.getElementById("input").value;
	//リクエストの初期化(GETで非同期通信）
	xhr.open("GET", url, true );
	//リクエストの送信
	xhr.send(null);
    //以下のデバグ文がいつ実行されるか確認
    console.log("after");
}
```

```html:ajaxform.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="sample.js"></script>
</head>
<body>
	INPUT: <input id="input" name="input" type="text">
	OUTPUT: <input id="output" name="output" type="text" value="">
	<button onclick="calculate();">Calculate</button>
</body>
</html>
```

-------
### Ajaxアプリの特徴
* テキストボックスのみ更新される
  - 画面のチラツキが解消
* サーバ通信中もクライアント側で処理を継続できる
  - サーバ通信中に、コンソールに"after"が出力されることを確認

-------
### XMLHttpRequestで同期通信を実施

`XMLHttpRequest.open`の3番目の引数に`false`を指定する。

```javascript:sample.js
function calculate() {
  //省略
  
	//リクエストの初期化(GETで同期通信）
	xhr.open("GET", url, false );
	//リクエストの送信
	xhr.send(null);
    //以下のデバグ文がいつ実行されるか確認
    console.log("after");
}
```

* 同期通信では、サーバ通信の完了後にコンソールに"after"が出力される。

[同期および非同期リクエスト](https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests) 参考


-------
### XMLHttpRequestでPOSTを送信

```java:PowServlet.java
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      //doGetと同じ処理
      //...
    }
```    

```javascript:sample.js
function calculate_POST() {
	const xhr = new XMLHttpRequest();
	//リクエストが成功したときのイベントを設定
	xhr.addEventListener("load", function() {
		const output = xhr.responseText; //二乗の結果
		//テキストボックスに表示
		document.getElementById("output").value = output;
	} ,false);

	//リクエストの初期化
	xhr.open("POST", "/SampleWeb/pow", true );
	//リクエストヘッダの指定
	xhr.setRequestHeader("content-type","application/x-www-form-urlencoded;charset=UTF-8");
	//リクエストの送信
	xhr.send("input=" + document.getElementById("input").value);
}
```

* `XMLHttpRequest.open`メソッドに"POST"を指定
* リクエストヘッダに`Content-Type`を指定
* `XMLHttpRequest.open`メソッドにリクエストボディ（パラメータ）を指定

-------
# 2. ライブラリでAjax


-------
## jQuery3の`ajax`メソッドを利用する

```js:sample.js
function calculate_jQuery() {
	const data = {
		input: document.getElementById("input").value
	};

	$.ajax({
		  type: "GET",
		  url: "/SampleWeb/pow",
		  data: data
	}).done(function( data, textStatus, jqXHR){ //成功した場合
		document.getElementById("output").value = data;

	}).fail(function(jqXHR, textStatus, errorThrown){ //失敗した場合
	   console.log("error", jqXHR);
	});
}
```

* オブジェクトを渡せる（`key=value`形式でない）
* 成功した場合の処理は`done`、失敗した場合は`fail`メソッドを使う

-------
## [補足] jQuery3からの場合

昔よく使われたsuccess、error、completeメソッドは、jQuery3から廃止された。

```js
//昔の書き方
$.ajax({
    url: "http://jsrun.it/assets/E/H/Z/t/EHZt3",
    success: function (data) {
        $("#results").append(data);
    },
    error: function () {
        alert("読み込み失敗");
    }
});
```

[jQuery3.0 アップグレードガイド](https://qiita.com/rana_kualu/items/65a4fb9f9b2bd3806598) 参考


-------
## [補足] Fetch API

`XMLHttpRequest`に替わる新しい機能。

https://developer.mozilla.org/ja/docs/Web/API/Fetch_API
https://qiita.com/tomoyukilabs/items/9b464c53450acc0b9574

-------
## [補足] Super Agent
Ajax専用ライブラリ。
https://github.com/visionmedia/superagent

2017年現在、jQueryは使われなくなりつつある

* JavaScriptの標準化が進み、jQueryを使う必要がなくなった
* React.jsなどjQueyrに代わるライブラリが出てきた

http://www.buildinsider.net/hub/survey/201606-popularjs

`$.ajax`を使うためにjQueryをロードするのは無駄なので、jQueryを使わないなら、これを使った方がよさそう。


-------
# 3. JSONとAjax


-------
## JSONとは

>JSON (JavaScript Object Notation)は、軽量のデータ交換フォーマットです。人間にとって読み書きが容易で、マシンにとっても簡単にパースや生成を行なえる形式です。

http://www.json.org/json-ja.html 引用

JavaScriptの標準機能でJSONに変換できる。

```javascript:ブラウザコンソール
a = {x:1, y:"a", z:[1,2,3]}
//オブジェクトをJSONに変換
b = JSON.stringify(a)
console.log(b)
// ⇒ "{"x":1,"y":"a","z":[1,2,3]}"
//JSONをオブジェクトに変換
c = JSON.parse(b)
console.log(c)
```


-------
## Ajaxで複数の情報
Ajax用のAPIは、JSONで返すのが一般的。

[Google Map API スタートガイド](https://developers.google.com/maps/documentation/geocoding/start?hl=ja)

[Nagoyaの緯度経度を返すAPI](https://maps.googleapis.com/maps/api/geocode/json?address=Nagoya)



-------
## Ajaxの"X"

XMLのこと。
もともとXMLを返すことを想定したたが、JSONの方が便利なためJSONで返すようになった。

XMLと比較したときのJSONのメリットは

* 人が読みやすい
 - 冗長でない
* プログラムにとって扱いやすい
 - JavaScriptのオブジェクト記法と同じ

http://uraway.hatenablog.com/entry/2015/12/26/XML%E3%81%A8%E3%81%AF%EF%BC%9F_JSON%E3%81%A8%E3%81%AF%EF%BC%9F
https://www.gixo.jp/blog/4196/

-------
### JSONとXMLの比較（作成中）

* TODO JSON利用者が増えているグラフを表示

-------
# 付録

-------
## Ajaxは流行った？

* タイトルに「Ajax」が含まれている本は、2006～2009年に発行されている。

[タイトルに"ajax"が含まれる書籍 - Amazon 検索](https://www.amazon.co.jp/gp/search/ref=sr_il_ti_stripbooks?rh=n%3A465392%2Cn%3A%21465610%2Cn%3A466298%2Cp_28%3Aajax%2Cp_45%3A0%2Cp_46%3Abefore%2Cp_47%3A2020&sort=date-asc-rank&unfiltered=1&ie=UTF8&qid=1508861636&lo=stripbooks)

-------
## CORS（作成中）

* JSONP


-------
## 参考サイト

* [新人プログラマですがjQueryのajaxがわからなすぎて勉強したまとめ](https://qiita.com/okumurakengo/items/53020dd97382d49621ce)
* [jQuery3.0 アップグレードガイド](https://qiita.com/rana_kualu/items/65a4fb9f9b2bd3806598)

-------
## JSONP