プログラミングで、通信処理などの時間のかかる処理を行う際に必要となってくるのが、非同期処理です。
JavaScriptでは、非同期処理を扱う方法の1つとして Promiseオブジェクトを活用する方法がありますが、ケースによってはコードが複雑となり、一見するとどのような処理が行われているのかが理解しづらい場合があります。
このような問題を解決するために活用できるのが、「async/await」 です。
これらのキーワードを活用することにより、非同期処理を視覚的に理解しやすくすることができます。
JavaScriptの “async/await” とは?
async/await は、非同期処理を同期的に実行するための機能です。
同じく、非同期処理を順に実行する方法の1つに、Promiseオブジェクトのthenメソッドを使用する方法がありますが、async/await は同等の処理をより視覚的に分かりやすいコードで記述することができる特徴を持っています。
“async/await”の使い方
async/await を使用する具体的な方法について、順に見ていきましょう。
基本構文
まずは、基本構文から解説していきます。
asyncは、対象の関数が非同期関数であることを示すキーワードです。
関数の頭に async を付けることで、その関数をPromiseオブジェクトを返す関数として定義することができます。
【基本構文】
async function sample() {
// 処理内容
}await は、 async関数の中でのみ使用できる演算子です。
awaitを使用すると、対象の処理を実行して Promiseオブジェクトが返されるまで、関数内の処理が一時停止します。
【基本構文】
async function sample() {
await 処理内容; // Promiseオブジェクトが返されるまでこの行で処理が一時停止する
}thenメソッドを繋いで非同期処理を順に実行するのと同じ処理を、awaitを使ってより見やすく記述することができます。
【基本構文】
async function sample() {
// 上から順に実行される
await 処理内容1;
await 処理内容2;
await 処理内容3;
}“async/await”で非同期処理を記述する
それでは、実際に async/await を使って処理を実行してみましょう。
asyncを使用して宣言した非同期関数は、戻り値が Promiseオブジェクトとなります。
関数内で return をした場合は resolve を実行し、例外処理などが発生した場合は reject を実行します。
return で指定した戻り値は、resolveの実行時に引数を渡すのと同じように扱われます。
await で Promiseオブジェクトの結果を待つことで、指定した戻り値を受け取ることができます。
【サンプルコード】
async function samlpeAsync() {
return 5;
}
async function asyncCall() {
const num = await samlpeAsync();
console.log(num);
}
asyncCall();【実行結果】
5上記のメソッドは、以下の Promise.then で実行した場合と同じ内容となります。
【サンプルコード】
function samlpeAsync() {
return new Promise((resolve, reject) => {
resolve(5);
});
}
samlpeAsync().then(val => {
console.log(val);
});Promise.thenを使わずに複数の非同期処理を実行する
冒頭で、async/await は thenメソッドと同等の処理をより見やすいコードで記述する方法だと説明しました。
ここで、2つのコードの違いを実際に確認してみましょう。
例として、以下の2つの Promise オブジェクトを返す関数をもとにコードを記述します。
【サンプルコード】
function wait2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
console.log("2秒経過");
resolve();
}, 2000);
});
}
function wait5Seconds() {
return new Promise(resolve => {
setTimeout(() => {
console.log("5秒経過");
resolve();
}, 5000);
});
}まず、これらの関数をそのまま実行すると、以下のような結果になります。
【実行される関数】
wait5Seconds();
wait2Seconds();
console.log("calling");【実行結果】
calling
2秒経過
5秒経過これらの処理を記述した順に実行させたい場合に、thenメソッドで記述すると以下のようなコードになります。
【サンプルコード】
wait5Seconds().then(() => {
return wait2Seconds();
}).then(() => {
console.log("calling");
});一方、async/await を使用して記述すると、以下のようなコードになります。
【サンプルコード】
async function asyncCall() {
await wait5Seconds();
await wait2Seconds();
console.log("calling");
}thenメソッドと比べると、どの処理をどの順番で実行しているのかが見やすくなったのが分かるでしょうか?
実行する非同期処理の数や、処理内容の複雑さが増すほど、この違いはコードの見やすさに大きく影響してきます。
“async/await”で並行処理を実装する
JavaScriptはシングルスレッドでしか動かない性質があるため、複数の処理を並列で走らせることができません。
JavaScriptはシングルスレッドで動作する仕様上、厳密には複数の処理を並列して実行することはできません。
ここまで記述してきた非同期処理も、複数のスレッドで同時に処理を行っているわけではなく、処理の実行タイミングを調整することで同時に処理しているように見えているだけとなります。
ですが、複数の非同期処理をまとめて実行することで、結果として並列処理に似た動き (並行処理) を行うことができます。
JavaScriptで非同期処理を行う場合は、Promise.all と組み合わせて使用します。
Promise.all は 待機状態の Promiseオブジェクトを引数に渡すことで、 それぞれの Promiseオブジェクトの結果が返されることを並行で待機することができるメソッドです。
async/await で Promise.all の結果を受け取ることにより、非同期処理を並行して行うことができます。
【サンプルコード】
function samlpeAsync(num) {
return new Promise(resolve => {
setTimeout(() => {
resolve(num);
}, num*1000 )
});
}
async function asyncCall() {
const func1 = samlpeAsync(3);
const func2 = samlpeAsync(5);
const func3 = samlpeAsync(2);
const [num1, num2, num3] = await Promise.all([func1, func2, func3]);
console.log(num1 + num2 + num3);
}
console.log("start");
asyncCall();
console.log("end");【実行結果】
start
end
10実行すると、非同期処理の結果がおよそ5秒ほどでコンソール表示されます。
通常の async/await で実行すると、各処理ごとに処理の完了を待機してから次の処理へと移るため、全てを結果を得るのにより多くの時間がかかってしまいます。
【サンプルコード】
async function asyncCall() {
// 全ての処理が完了するのに 10秒ほどかかってしまう
const num1 = await samlpeAsync(3);
const num2 = await samlpeAsync(5);
const num3 = await samlpeAsync(2);
console.log(num1 + num2 + num3);
}
asyncCall();Promise.all を使って並行処理することで、3つの処理の中で最も時間のかかる func2の処理が完了した段階で全ての処理結果を受け取ることができています。
また、Promise.all は使用せずに、以下のような構文で記述することもできます。
【サンプルコード】
async function asyncCall() {
const num1 = samlpeAsync(3);
const num2 = samlpeAsync(5);
const num3 = samlpeAsync(2);
console.log(await num1 + await num2 + await num3);
}
asyncCall();まとめ
いかがでしたか?今回は、JavaScriptで async/await を使用する方法について解説しました。
非同期処理は仕様上、コード内容が複雑になりがちなため、慣れないうちは理解するのが難しいと感じてしまうかもしれませんが、アプリケーションを開発する上では避けて通れない重要な機能です。
実践なども交えながら、しっかりと機能を理解して開発に役立てていけるよう、何度も反復して練習しておきましょう。
JavaScriptの勉強方法は?
書籍やインターネットで学習する方法があります。昨今では、YouTubeなどの動画サイトやエンジニアのコミュニティサイトなども充実していて多くの情報が手に入ります。
そして、より効率的に知識・スキルを習得するには、知識をつけながら実際に手を動かしてみるなど、インプットとアウトプットを繰り返していくことが重要です。特に独学の場合は、有識者に質問ができたりフィードバックをもらえるような環境があると、理解度が深まるでしょう。
ただ、JavaScriptに限らず、ITスキルを身につける際、どうしても課題にぶつかってしまうことはありますよね。特に独学だと、わからない部分をプロに質問できる機会を確保しにくく、モチベーションが続きにくいという側面があります。独学でモチベーションを維持する自信がない人にはプログラミングスクールという手もあります。費用は掛かりますが、その分スキルを身につけやすいです。しっかりと知識・スキルを習得して実践に活かしたいという人はプログラミングスクールがおすすめです。
プログラミングスクールならテックマニアがおすすめ!
ITスキル需要の高まりとともにプログラミングスクールも増えました。しかし、どのスクールに通うべきか迷ってしまう人もいるでしょう。そんな方にはテックマニアをおすすめします!これまで多くのITエンジニアを育成・輩出してきたテックマニアでもプログラミングスクールを開講しています。
<テックマニアの特徴>
・たしかな育成実績と親身な教育 ~セカンドキャリアを全力支援~
・講師が現役エンジニア ~“本当”の開発ノウハウを直に学べる~
・専属講師が学習を徹底サポート ~「わからない」を徹底解決~
・実務ベースでスキルを習得 ~実践的な凝縮カリキュラム~
このような特徴を持つテックマニアはITエンジニアのスタートラインとして最適です。
話を聞きたい・詳しく知りたいという方はこちらからお気軽にお問い合わせください。