LoginSignup
0
0

【非同期処理】Promise,async/awaitについて

Posted at

まず、反対の同期処理とは

プログラムの記述順序通りに実行され結果が返る。
add関数が実行され計算結果がリターンされてから、hogeに代入している。

JavaScriptは「UIスレッド」と呼ばれるメインスレッド上で処理を1つ1つ順番に実行していくことしかできない。

時間のかかる処理を行うとJavascriptはその処理にUIスレッドを占有してしまう。処理完了まで一切何もできなくなる。クリックもローダーやプログレスバーの表示もできない。つまり、パソコンがフリーズしているように見えやすい

test1.js
//例1
cosnt add = (a, b) => {
	return a + b
}

let hoge = 0;
hoge = add(10, 100)
console.log(hoge) //表示は「110」
test2.js
//例2
//10秒間UIスレッドを独占する。その間は操作できない
function sleep(msec) {
	var start = new Date();
	while (new Date() - Start < msec);
	alert("処理完了");
}

sleep(10000);

以下本題⇓

非同期処理とは

例:Amazon, GoogleMapとか

超簡単に言うと:
非同期処理は、あるタスクが実行している際に、他のタスクが別の処理を実行できる方式である。

メリット:ユーザ体験が上がる!
2つの例で見てきたようにサクサク動きながらデータを取ってこようと思ったら非同期処理を活用しないと著しくユーザ体験が低くなってしまう。

自分がよくしてしまったmiss!⇓

test.js
// 第3引数がfalseで同期
new XMLHttpRequest().open("GET", "https://zip-cloud.appspot.com/api/search?zipcode=7830060",false);

警告文
解説:XMLHttpRequestは非同期処理で使用しなければならない。さもないと、ユーザー体験に悪影響を与える...
(読みにくいの改行してます)

test.js
// Synchronous XMLHttpRequest on the main thread is deprecated 
// because of its detrimental effects to the end user's experience. 
// For more help, check https://xhr.spec.whatwg.org/.

Promise型について

Promise型は非同期処理を実現する
Promiseを作るには非同期処理の内容を記述した関数を引数に指定し、Promiseのインスタンスを生成します。
基本的な形は⇓

test.js
new Promise((resolve, reject) => {
//処理を書く
});

APIの取得について

(ここが難しいというか、理解しづらい。)
JavaScriptでAPI取得する

test1.js
function question() {
	return new Promise((resolve, reject) => {
		let req = new XMLHttpRequest();
		req.onreadystatechange = function() {
			if (req.readyState == 4) { // 通信の完了時
				if (req.status == 200) { // 通信の成功時
					let data = eval('(' + req.responseText + ')');
					resolve(data.answer);
				}
			} else{
				console.log("通信中...");
			}
		}
		req.open('GET', 'エンドポイント', true);
		req.send(null);
	});
}
question().then(
	function(val) {
		console.log('answer:' + val)
	},
	function(err) {
		console.log(err)
	}
);

ここでPromise型をうまく使うと効果抜群!
めっちゃ簡単に言うと:
json取得 → 画像読み込み完了 → 表示の非同期処理の実行
この順番をきれいに整理してUXをよくするってことだと思う。

つまり、読み込み完了まではローディング画像をセットし、完了後に読み込んだ画像を表示している。

test2.js
function question() {
	return new Promise((resolve, reject) => {
		let req = new XMLHttpRequest()
		req.onreadystatechange = function() {
			if (req.readyState == 4) { // 通信の完了時
				if (req.status == 200) { // 通信の成功時
					let data = eval('(' + req.responseText + ')')
					resolve(data)//先ほどはdata.answerだった
				}else {
					reject(req.status)//先ほどからの付け加え
				}
			} else{
				console.log("通信中...")
			}
		}
		req.open('GET', 'エンドポイント', true)
		req.send(null)
	})
}
//以下Promise型をうまく使えているところ
function imageLoaded(src) {
	return new Promise((resolve, reject) => {
		let img  = new Image()
		img.src = src
		img.addEventListener("load", () => {
			resolve(src)
		})
	})
}
question().then(
	(data) => {
		this.answer = data.answer
		this.status = 1
		return imageLoaded(data.image)
	},
	(err) => {
		console.log(err)
	}
).then(
	(src) => {
		this.image = src
		this.status = 2
	}
)

async/await

以下、async/awaitで書き換えると、めちゃシンプル
関数の前にasyncを付けると、async関数になる。
演算子awaitはasync関数の中でのみ使えるもので、対象のPromiseが成功するまで待ってくれます。 さきほどのコードのプロミスの連鎖箇所をasync,awaitで書き換えています。

test3.js
let display = async () => {
	try {
		await question()
		await imageLoaded()
	} catch(err) {
		console.log("エラーが起こりました:" + err)
	}
}
display()

最後に

わかりにくいところ、おかしいところあれば教えてくださるとうれしいです。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0