まず、反対の同期処理とは
プログラムの記述順序通りに実行され結果が返る。
add関数が実行され計算結果がリターンされてから、hogeに代入している。
⇓
JavaScriptは「UIスレッド」と呼ばれるメインスレッド上で処理を1つ1つ順番に実行していくことしかできない。
⇓
時間のかかる処理を行うとJavascriptはその処理にUIスレッドを占有してしまう。処理完了まで一切何もできなくなる。クリックもローダーやプログレスバーの表示もできない。つまり、パソコンがフリーズしているように見えやすい
//例1
cosnt add = (a, b) => {
return a + b
}
let hoge = 0;
hoge = add(10, 100)
console.log(hoge) //表示は「110」
//例2
//10秒間UIスレッドを独占する。その間は操作できない
function sleep(msec) {
var start = new Date();
while (new Date() - Start < msec);
alert("処理完了");
}
sleep(10000);
以下本題⇓
非同期処理とは
例:Amazon, GoogleMapとか
超簡単に言うと:
非同期処理は、あるタスクが実行している際に、他のタスクが別の処理を実行できる方式である。
メリット:ユーザ体験が上がる!
2つの例で見てきたようにサクサク動きながらデータを取ってこようと思ったら非同期処理を活用しないと著しくユーザ体験が低くなってしまう。
自分がよくしてしまったmiss!⇓
// 第3引数がfalseで同期
new XMLHttpRequest().open("GET", "https://zip-cloud.appspot.com/api/search?zipcode=7830060",false);
警告文
解説:XMLHttpRequestは非同期処理で使用しなければならない。さもないと、ユーザー体験に悪影響を与える...
(読みにくいの改行してます)
// 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のインスタンスを生成します。
基本的な形は⇓
new Promise((resolve, reject) => {
//処理を書く
});
APIの取得について
(ここが難しいというか、理解しづらい。)
JavaScriptでAPI取得する
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をよくするってことだと思う。
つまり、読み込み完了まではローディング画像をセットし、完了後に読み込んだ画像を表示している。
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で書き換えています。
let display = async () => {
try {
await question()
await imageLoaded()
} catch(err) {
console.log("エラーが起こりました:" + err)
}
}
display()
最後に
わかりにくいところ、おかしいところあれば教えてくださるとうれしいです。