■ はじめに
https://dk521123.hatenablog.com/entry/2021/01/14/101645
で、外部APIにアクセスしてデータ取得することを行った。 その際、非同期処理になる。 そこで、JavaScript/TypeScriptでの非同期処理を学ぶ。
目次
【1】関連用語 1)async 2)await 3)Promise 【2】サンプル 例1:await で待たされるダメな実装 例2:効率的な作業をした実装 - Promise.all() 例3:例2のVue+TypeScript版
【1】関連用語
1)async
* 以下のサイトを一読しておくといい。(物凄く分かりやすい)
https://qiita.com/7tsuno/items/6d5a27ffe9143b35defe
* async(Asynchronous) = 非同期 * 対象関数が非同期であることを宣言する
async(JavaScript)
async function demoAsynchronous() { return 'Hello world!!'; }
2)await
* 非同期処理を待つ => Promiseの結果が出るまで待つ
await(JavaScript)
async function demoAsynchronous2() { const result = await demoPromise('Mike'); console.log(result); }
3)Promise
* 非同期処理で完了した際のレスポンスを表すオブジェクト
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise
* Promise の説明が以下が分かりやすい。
* 以下の関連記事で行ったFutureオブジェクトと同じ => 『処理の実行担当者は、処理が渡されると別スレッド上で処理を開始して、 メインスレッドには即座にFutureオブジェクトを返すこと』
https://dk521123.hatenablog.com/entry/2014/01/18/000804
Promise(JavaScript)
function demoPromise(name) { // 引数「resolve」に取得したい値を設定することで // 非同期処理の結果を格納することができる return new Promise(function(resolve) { resolve(`Hi, ${name}`); }); }
Promise 状態
1)Fulfilled ... 成功 2)Rejected ... 失敗 3)Pending ... ペンディング中 Promiseの詳細は、以下のサイトを参照。
https://qiita.com/sotszk/items/f23199e864cba47455ce
【2】サンプル
https://qiita.com/7tsuno/items/6d5a27ffe9143b35defe
の説明が分かりやす過ぎたので、理解を深めるために 自分でも色々と弄れるサンプルを作ってみた。 (f12なので、ログを出しながら動かせば理解しやすいと思う)
例1:await で待たされるダメな実装
<!DOCTYPE html> <html lang="jp"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Hello World!</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <!-- ★HTML部分★ --> <div id="app-x"> <div><button v-on:click="onClickEvent">Click me!</button></div> <div><p>{{ message }}</p></div> </div> <script> <!-- ★JS部分★ --> var dummyWork = (process, requiredTime) => { var waittingTime = requiredTime * 1000; console.log("Start work[" + process + "] - " + waittingTime); return new Promise((resolve, reject) => { setTimeout(() => { resolve("Done"); console.log("Done - " + process); }, waittingTime); }); }; async function cook() { // 麺担当に麺をゆでてもらう const noodles = await dummyWork('noodle', 3); // スープ担当にスープを作ってもらう const soup = await dummyWork('soup', 2); // 具担当にチャーシューを切ってもらう const pork = await dummyWork('pork', 1); // ラーメンを完成させる。 const ramen = await dummyWork('ramen', 1); return "Done!!"; }; var app = new Vue({ el: '#app-x', data: { message: 'Click the button', }, methods: { onClickEvent: function () { const startTime = performance.now(); this.message = "Start work!"; cook().then(value => { console.log(value); // => Done!! this.message = value; const endTime = performance.now(); console.log("Time : " + (endTime - startTime)); }); } } }); </script> </body> </html>
出力結果
Start work[noodle] - 3000 Done - noodle Start work[soup] - 2000 Done - soup Start work[pork] - 1000 Done - pork Start work[ramen] - 1000 Done - ramen Done!! Time : 7037.229999999909
例2:効率的な作業をした実装 - Promise.all()
<!DOCTYPE html> <html lang="jp"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Hello World!</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <!-- ★HTML部分★ --> <div id="app-x"> <div><button v-on:click="onClickEvent">Click me!</button></div> <div><p>{{ message }}</p></div> </div> <script> <!-- ★JS部分★ --> var dummyWork = (process, requiredTime) => { var waittingTime = requiredTime * 1000; console.log("Start work[" + process + "] - " + waittingTime); return new Promise((resolve, reject) => { setTimeout(() => { resolve("Done"); console.log("Done - " + process); }, waittingTime); }); }; async function cook() { // 麺・スープ・チャーシューを一気に依頼 const processes = [ { name: "noodles", requiredTime: 3 }, { name: "soup", requiredTime: 2 }, { name: "pork", requiredTime: 1 } ]; const [noodles, soup, pork] = await Promise.all( processes.map(process => dummyWork(process.name, process.requiredTime))); // ラーメンを完成させる。 const ramen = await dummyWork('ramen', 1); return "Done!!"; }; var app = new Vue({ el: '#app-x', data: { message: 'Click the button', }, methods: { onClickEvent: function () { const startTime = performance.now(); this.message = "Start work!"; cook().then(value => { console.log(value); // => Done!! this.message = value; const endTime = performance.now(); console.log("Time : " + (endTime - startTime)); }); } } }); </script> </body> </html>
出力結果
Start work[noodles] - 3000 Start work[soup] - 2000 Start work[pork] - 1000 Done - pork Done - soup Done - noodles Start work[ramen] - 1000 Done - ramen Done!! Time : 4027.9150000005757
例3:例2のVue+TypeScript版
<template> <div id="app-x"> <div><button v-on:click="onClickEvent">Click me!</button></div> <div><p>{{ message }}</p></div> </div> </template> <script lang="ts"> import { Component, Vue, Prop } from "vue-property-decorator"; @Component export default class Home extends Vue { public message?: string = "Click here"; private onClickEvent() { const startTime = performance.now(); this.message = "Start work!"; this.cook().then(value => { console.log(value); // => Done!! this.message = value; const endTime = performance.now(); console.log("Time : " + (endTime - startTime)); }); } private async cook() { // 麺・スープ・チャーシューを一気に依頼 const processes = [ { name: "noodles", requiredTime: 3 }, { name: "soup", requiredTime: 2 }, { name: "pork", requiredTime: 1 } ]; const [noodles, soup, pork] = await Promise.all( processes.map(process => this.dummyWork( process.name, process.requiredTime))); // ラーメンを完成させる。 const ramen = await this.dummyWork('ramen', 1); return "Done!!"; } private dummyWork(process: string, requiredTime: number) { const waittingTime = requiredTime * 1000; console.log("Start work[" + process + "] - " + waittingTime); return new Promise((resolve, reject) => { setTimeout(() => { resolve("Done"); console.log("Done - " + process); }, waittingTime); }); } } </script>
関連記事
TypeScript ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2020/12/21/180904
axios ~ 外部API通信ライブラリ ~
https://dk521123.hatenablog.com/entry/2021/01/14/101645
Jestを使った Vue / TypeScript の単体試験 ~ 非同期編 ~
https://dk521123.hatenablog.com/entry/2021/03/13/000000
Future パターン
https://dk521123.hatenablog.com/entry/2014/01/18/000804
タイマー処理 ~ setTimeout / setInterval etc ~
https://dk521123.hatenablog.com/entry/2021/02/01/000000
処理時間計測 ~ performance.now() ~
https://dk521123.hatenablog.com/entry/2021/02/05/000000
非同期に関する用語
https://dk521123.hatenablog.com/entry/2017/08/27/230218