JavaScriptによる非同期処理
こんにちはあっくんです。僕の肌荒れが最高潮に達してきました。もともとのアレルギー体質と日々の不眠とかから来てるかも知れません。健康って本当に大切ですね。明日、また病院に行ってみます。
それでは,JavaScriptによる非同期処理をやっていきましょー!!
JavaScriptによる非同期処理
非同期処理を書くための仕組みの一つであるPromiseがあります。asynccとawitという非同期処理を短く方法もあります。
非同期処理とは
非同期処理とは時間のかかる処理は終了をまたずに先に進め、処理が終わったタイミングで関数を実行するという方式です。
JavaScriptは基本的にシングルスレッドのプログラミング言語です。処理は1つずつ終わるのを街、次の処理へと進んで行きます。このシングルスレッドの方式は、通信などの待機時間がある処理で問題になます。待ち時間が終わるまでにすべての処理が止まり、操作不能になるからです。
例、処理1,2,5,6と進んだあとに3,4を実行します。setTimeout()は一定時間待機したあとに引数の関数を実行する命令です。
<html>
<script>
// メインの処理の流れ。
console.log("処理1");
console.log("処理2");
// 100ミリ秒後に実行する処理
setTimeout(() => {
console.log("処理2");
console.log("処理3");
}, 100);
// メインのしょりの流れ
console.log("処理5");
console.log("処理6");
</script>
</html>
Code language: HTML, XML (xml)
非同期処理はコールバック関数を使います。非同期の処理が複数にになることもあります。その場合、コールバック関数のネストは深くなり、プログラムはみにくくなります。
こうした問題を解決するために、Promiseという仕組みがあります。
例、非同期処理が入れ子になったプログラム。
<html>
<script>
console.log("処理1");
// 100ミリ秒待って実行
setTimeout(() => {
console.log("処理A");
// 100ミリ秒待って実行
setTimeout(() => {
console.log("処理B");
// 100ミリ秒待って実行
setTimeout(() => {
console.log("処理C");
// 100ミリ秒待って実行
setTimeout(() => {
console.log("処理D");
// 100ミリ秒待って実行
setTimeout(() => {
console.log("処理E");
}, 100);
}, 100);
}, 100);
}, 100);
}, 100);
console.log("処理2");
</script>
</html>
Code language: HTML, XML (xml)
Promise
Promiseとは、約束です。Promiseオブジェクトは、後で処理することを約束して、先にすすむためのものです。
Promiseオブジェクトは、new Promise(関数)と、コールバック関数を引数にしてインスタンスを作ります。コールバック関数は、resolve(解決)とreject(拒否)という2つの関数を引数に取ります。そして、時間がかかる処理をしたあと、正常に終了すればresolve()関数を、異常に終了すればreject()関数を実行します。
構文
new Promise((resolve, reject) => {
時間のかかる処理
正常に終了したとき終了したときしたとき()を実行実行
異常に終了したとき終了したときしたとき()を実行実行
})
Code language: JavaScript (javascript)
Promiseオブジェクトには処理が終わったあとに、続きの処理をするためのメソッドがあります。最も一般的なメソッドはthen(関数)です。then()のコールバック関数は、resolve()やreject()を実行すると呼び出されます。resolve(),reject()に引数を設定したときは、コールバック関数の値を受け取れます。
構文
new Promise((resolve, reject) => {
時間のかかる処理
正常に終了したとき終了したときしたとき(dateA)を実行実行
異常に終了したとき終了したときしたとき(dataB)を実行実行
})
.then(dataA => {
resolve()を実行した時の処理した時の処理時の処理
resolve()の引数を
}, dataB => {
reject()を実行した時の処理した時の処理時の処理(書かなくてもよい
reject()の引数を
});
Code language: JavaScript (javascript)
.then()は、再びPromiseオブジェクトを返します。そのため、.then()のあとに、さらに.thenを書くことができます。
構文
new Promise((resolve, reject) => {
})
.then(dataA => {
})
.then(dataA => {
})
.then(dataA => {
});
Code language: JavaScript (javascript)
.then()のコールバック関数の戻り値としてPromiseオブジェクトを書いたときは、その処理の終了を待って、次の.then()を実行します。戻り値がPromiseオブジェクトでないときは待機せず、すぐに次の制御が移ります。
構文
new Promise((resolveA, reject) => {
時間のかかる処理
正常に終了したときは()を実行実行
})
.then(data => {
resolveA()を実行したときの処理
変数P数P= new Promise((resolveB, reject) => {
時間のかかる処理
正常に終了したときは()を実行実行
})
return 変数P数P;
})
.then(data => {
resolveB()を実行したときの処理
変数P数P= new Promise((resolveC, reject) => {
時間のかかる処理
正常に終了したときは()を実行実行
})
return 変数P数P;
})
Code language: JavaScript (javascript)
例、Promise。
<html>
<script>
console.log("処理1");
new Promise((resolve, reject) => {
// 100ミリ秒待って実行
setTimeout(() => {
console.log("処理A");
resolve();
}, 100);
})
.then((d) => {
return new Promise((resolve, reject) => {
// 100ミリ秒待って実行
setTimeout(() => {
console.log("処理B");
resolve();
}, 100);
});
})
.then((d) => {
return new Promise((resolve, reject) => {
// 100ミリ秒待って実行
setTimeout(() => {
console.log("処理C");
resolve();
}, 100);
});
})
.then((d) => {
return new Promise((resolve, reject) => {
// 100ミリ秒待って実行
setTimeout(() => {
console.log("処理D");
resolve();
}, 100);
});
})
.then((d) => {
return new Promise((resolve, reject) => {
// 100ミリ秒待って実行
setTimeout(() => {
console.log("処理E");
resolve();
}, 100);
});
});
console.log("処理2");
</script>
</html>
Code language: HTML, XML (xml)
例、Promise。非同期処理を関数を使って見やすくします。
<html>
<script>
// 待機用の関数
function wait(msg) {
// Promiseオブジェクトを戻り値にする
return new Promise((resolve, reject) => {
// 100ミリ秒待って実行
setTimeout(() => {
console.log(msg);
resolve();
}, 100);
});
}
console.log("処理1");
wait("処理A")
.then((d) => {
return wait("処理B");
})
.then((d) => {
return wait("処理C");
})
.then((d) => {
return wait("処理D");
})
.then((d) => {
return wait("処理E");
});
console.log("処理2");
</script>
</html>
Code language: HTML, XML (xml)
Promiseのインスタンスメソッド
Promiseオブジェクトのインスタンスメソッドは.3種類あります。
Promiseオブジェクトのインスタンスメソッド
.then(f1, f2)
resolve()のときは関数f1, reject()のときは関数f2を実行。
.catch(f1)
reject()のときは関数f1を実行。
.finally(f1)
resolve()でもreject()でも関数f1を実行。
.then()は(第1引数のみを使い)正常時の処理、 .catch()は異常時の処理、 .finally()は両方で行う最終処理で使い分けます。
例、Promise。reject()が実行されたら、間にあるresolve()は一挙に飛ばされます。
<html>
<script>
// 待機用の関数
function wait(msg, isOk = true) {
// Promiseオブジェクトを戻り値にする。
return new Promise((resolve, reject) => {
// 100ミリ秒待って実行
setTimeout(() => {
console.log(msg);
if (isOk) {
// isOk我trueなら解決
resolve();
} else {
// isOkがfalseなら拒否
reject();
}
}, 100);
});
}
wait("処理A", false) //ここでrejectに
.then(
(d) => {
return wait("処理B 成功");
},
(d) => {
return wait("処理B 失敗");
}
)
.then((d) => {
return wait("処理C 成功", false);
})
.then((d) => {
return wait("処理D 成功");
})
.then((d) => {
return wait("処理E 成功");
})
.catch((d) => {
return wait("処理F 失敗");
})
.finally((d) => {
return wait("処理G 終了");
});
</script>
</html>
Code language: HTML, XML (xml)
例、Promise。throw文をつかって、処理C, 処理Dを飛ばします。
<html>
<script>
// 待機用の関数
function wait(msg) {
// Promiseオブジェクトを戻り値にする
return new Promise((resolve, reject) => {
// 100ミリ秒待って実行
setTimeout(() => {
console.log(msg);
resolve();
}, 100);
});
}
wait("処理A")
.then((d) => {
throw new Error("Oh!"); //例外を起こす
return wait("処理B");
})
.then((d) => {
return wait("処理C");
})
.then((d) => {
return wait("処理D");
})
.catch((d) => {
return wait("処理E");
})
.finally((d) => {
return wait("処理F");
});
</script>
</html>
Code language: HTML, XML (xml)
Promiseの静的メソッド
Promiseの静的メソッドは複数のPromiseをまとめて扱えます。 並列の処理です。
Promiseオブジェクトの静的メソッド
.all(a)
Promiseの配列aが全て解決すれば、解決とみなして結果の配列をあとの処理に送る。
1つでも拒否されれば拒否と見なし、結果をあとの処理に送ります。
.any(a)
Promiseの配列aが1つでも解決すれば、解決と見なして結果をあとの処理に送る。全て拒否すれば拒否と見なし、結果をあとの処理に贈ります。
.allSettled(a)
Promiseの配列aの処理が全て終われば、解決とみなしてすべての結果を配列にして送ります。
.race(a)
Promiseの配列aの処理が1つでも終われば次の処理に移行します。その1つの処理が解決なら解決と見なし、拒否なら拒否とみなします。
例、Promise.all()。 全てが解決するか、拒否が起きれば、先に進みます。
<html>
<body>
<script>
// 待機用の関数
function p(tm, isResolve = true) {
// Promiseオブジェクトを戻り値にする
return new Promise((resolve, reject) => {
// tmミリ秒待って実行
setTimeout(() => {
// コンソールに情報を出力
console.log(tm, isResolve ? "resolve" : "reject");
if (isResolve) {
// isResolveがtrueなら解決
resolve(`${tm}:ok`);
} else {
// isResolveがfalseなら拒否
reject(`${tm}:err`);
}
}, tm);
});
}
// Promise.all()その1
setTimeout(() => {
console.log("--- Promise.all() その1 ---");
// Promiseオブジェクトの配列を作成
const arr = [p(1, true), p(2, true), p(3, true)];
// Promise.all()の処理
Promise.all(arr)
.then((data) => {
// 成功時
console.log("--> then :", data);
})
.catch((data) => {
// 失敗
console.log("--> catch :", data);
});
}, 0);
// Promise.all()その2
setTimeout(() => {
console.log("--- Promise.all() その2 ---");
// Promiseオブジェクトの配列を作成
const arr = [p(1, true), p(2, false), p(3, true)];
// Promise.all()の処理
Promise.all(arr)
.then((data) => {
// 成功時
console.log("--> then :", data);
})
.catch((data) => {
// 失敗時
console.log("--> catch :", data);
});
}, 100);
</script>
</body>
</html>
Code language: HTML, XML (xml)
例、Promise.any()。 全てが拒否されるか、解決が起きれば先に進ます。
<html>
<script>
// 待機用の関数
function p(tm, isResolve = true) {
// Promiseオブジェクトを戻り値にする
return new Promise((resolve, reject) => {
// tmミリ秒待って実行
setTimeout(() => {
// コンソールに情報を出力
console.log(tm, isResolve ? "resolve" : "reject");
if (isResolve) {
// isResolveがtrueなら解決
resolve(`${tm}:ok`);
} else {
// isResolveがfalseなら拒否
reject(`${tm}:err`);
}
}, tm);
});
}
// Promise.any()その1
setTimeout(() => {
console.log("--- Promise.any() その1 ---");
// Promiseオブジェクトの配列を作成
const arr = [p(1, false), p(2, true), p(3, false)];
Promise.any(arr)
.then((data) => {
// 成功時
console.log("--> then :", data);
})
.catch((data) => {
// 失敗時
console.log("--> catch :", data);
});
}, 0);
// Promise.any()その2
setTimeout(() => {
console.log("--- Promise.any() その2 ---");
// Promise.any()の処理
const arr = [p(1, false), p(2, false), p(3, false)];
// Promise.any()の処理
Promise.any(arr)
.then((data) => {
// 成功時
console.log("--> then :", data);
})
.catch((data) => {
// 失敗時
console.log("--> catch:", data);
});
}, 100);
</script>
</html>
Code language: HTML, XML (xml)
例、Promise.allSettled()。 全ての処理が終われば、先に進みます。全ての結果を配列で受け取ります。
<html>
<script>
// 待機用の関数
function p(tm, isResolve = true) {
// Promiseオブジェクトを戻り値にする
return new Promise((resolve, reject) => {
// tmミリ秒待って実行
setTimeout(() => {
// コンソールに出力
console.log(tm, isResolve ? "resolve" : "reject");
if (isResolve) {
// isResolveがtrueなら解決
resolve(`${tm}:ok`);
} else {
// isResolveがfalseなら拒否
reject(`${tm}:err`);
}
}, tm);
});
}
// Promiseオブジェクトの配列を作成
const arr = [p(1, false), p(2, true), p(3, false)];
// Promise.allSettled()の処理
Promise.allSettled(arr).then((data) => {
console.log("--> then :", data);
});
</script>
</html>
Code language: HTML, XML (xml)
例、 Promise.race()。 最初の1つの処理が終われば、先に進みます。解決でも拒否でも構いません。
<html>
<script>
// 待機用の関数
function p(tm, isResolve = true) {
// Promiseオブジェクトを戻り値にする
return new Promise((resolve, reject) => {
// tmミリ秒待って実行
setTimeout(() => {
// コンソールに出力
console.log(tm, isResolve ? "resolve" : "reject");
if (isResolve) {
// isResolveがtrueなら解決
resolve(`${tm}:ok`);
} else {
// isResolveがfalseなら拒否
reject(`${tm}:err`);
}
}, tm);
});
}
// Promise.race()その1
setTimeout(() => {
console.log("--- Promise.race() その1 ---");
// Promiseオブジェクトの配列を作成
const arr = [p(1, true), p(2, false), p(3, true)];
Promise.race(arr)
.then((data) => {
// 成功時
console.log("--> then : ", data);
})
.catch((data) => {
// 失敗時
console.log("--> catch :", data);
});
}, 0);
// Promise.race()その2
setTimeout(() => {
console.log("--- Promise.race() その2 ---");
// Promiseオブジェクトの配列を作成
const arr = [p(1, false), p(2, true), p(3, false)];
// Promise.race()の処理
Promise.race(arr)
.then((data) => {
// 成功時
console.log("--> then :", data);
})
.catch((data) => {
// 失敗時
console.log("--> catch :", data);
});
}, 100);
</script>
</html>
Code language: HTML, XML (xml)
asyncとawait
asyncは非同期という意味です。 awaitは待つという意味です。
asyncとawaitを使った書き方でシンプルに非同期処理ができます。
async functionと書くことで、その関数は非同期処理を扱う関数になります。async function内では、非同期の関数の前にawaitをつけることで、Promiseの処理を待ってからプログラムを進めます。awaitをつけた関数の戻り値は、resolve()の引数になります。
構文
async function 関数名数名引数) {
処理
await 非同期の関数期の関数()
変数= await 非同期の関数期の関数()
//非同期の関数内で、resolve(v)を実行したなら、vが変数に入る。
処理
}
Code language: JavaScript (javascript)
例、async await。
<html>
<script>
// 待機用の関数
function wait(msg, isResolve = true) {
// Promiseオブジェクトを戻り値にする
return new Promise((resolve, reject) => {
// 100ミリ秒待って実行
setTimeout(() => {
if (isResolve) {
if (isResolve) {
// isResolveがtrueなら解決
resolve(msg);
} else {
// isResolveがfalseなら拒否
reject(`error (${msg}`);
}
}
}, 100);
});
}
// async実験用の関数
async function exec() {
console.log("--- 処理開始 ---");
console.log(await wait("処理A"));
console.log(await wait("処理B"));
console.log("処理途中");
const c = await wait("処理C");
const d = await wait("処理D");
console.log(c);
console.log(d);
console.log("--- 処理終了 ---");
}
// 処理の開始
console.log("--> 処理1");
console.log("--> exec()", exec());
console.log("--> 処理2");
</script>
</html>
Code language: HTML, XML (xml)
例、awaitの処理をtry catch文で加工と、reject()をcatchで捕まえられます。
<html>
<script>
// 待機用の関数
function wait(msg, isResolve = true) {
// Promiseオブジェクトを戻り値にする
return new Promise((resolve, reject) => {
// 100ミリ秒待って実行
setTimeout(() => {
if (isResolve) {
// isResolveがtrueなら解決
resolve(msg);
} else {
// isResolveがfalseなら拒否
reject(`error (${msg})`);
}
}, 100);
});
}
// async実験用の関数
async function exec() {
console.log("--- 処理開始 ---");
console.log(await wait("処理A"));
console.log(await wait("処理B"));
// try catch文
try {
// 例外が発生するかも知れない処理
console.log(await wait("処理C", false));
console.log(await wait("処理D"));
} catch (e) {
// 例外発生時の処理
console.log("例外発生", e);
}
console.log("--- 処理終了 ---");
}
// 処理の開始
exec();
</script>
</html>
Code language: HTML, XML (xml)
読んでいただいて、ありがとうございました!JavaScript完全入門は2021年、2月発売です。