はじめに
- JsのPromise処理を記述するのをサボってしまったため、Lambdaの処理は成功しているのにアプリケーション側へデータが送信できない不具合があったので、その凡ミスを復習も兼ねて見直しするために残します。
環境
- Mac
- エディタ:VsCode
- node:v20.9.0
前提
- VsCodeのRun and Debugで実行して確認できる状況
- 設定の仕方は下記の記事を参照にしてください
- 【Node.js】Visual Studio Code 上で JavaScript を実行する
基本的なJsの処理
- 同期処理(sync)と非同期処理(async)があって、基本的にはコードを上から順番に処理していくので、1つの処理が完了したら、次の処理を実行する流れになる(同期処理)
- 非同期処理も、基本的には上から順に処理していくけど、ひとつの非同期処理が終わるのを待たずに次の処理を実行してしまう=処理を待つことができない。
function taskA() {
console.log("タスクAを実行 at " + Date.now());
}
function taskB() {
console.log("タスクBを実行 at " + Date.now());
}
function taskC() {
console.log("タスクCを実行 at " + Date.now());
}
taskA();
setTimeout(() => {
taskB();
}, 1000);
taskC();
- 上記のコード例だと、見た目上はタスクA → タスクB → タスクCという流れになっているけど、実際は下記のようになる。
- 処理を待ってくれないので、先にタスクCが実行される。(これがLambda関数をnodeで書く際に、Promiseを書かないとアプリケーション側との送受信する場合、処理を待たずにLambda関数が終わってしまって、Lambda関数では処理がうまくいっている風になるけど、アプリケーション側では値が渡されていない現象が起きるので注意。)
Promise処理
- 先ほどのコードにPromise処理を追加して、実行してみると実行順番はA→B→Cになる
function taskA() {
console.log("タスクAを実行 at " + Date.now());
}
function taskB() {
console.log("タスクBを実行 at " + Date.now());
}
function taskC() {
console.log("タスクCを実行 at " + Date.now());
}
taskA();
new Promise((resolve) => {
setTimeout(() => {
taskB();
resolve();
}, 1000);
}).then(() =>{
taskC();
})
Promiseの状態
- 待機 (pending): 初期状態。成功も失敗もしていない
- 履行 (fulfilled): 処理が成功して完了している
- 拒否 (rejected): 処理が失敗している
Promiseインスタンスの状態は作成時にPendingというPromiseStatusになる。処理が成功した場合、PromiseStatusはresolvedに変化し、処理が失敗した場合、PromiseStatusはrejectedに変化する
基本的な書き方
- サイトによって書き方が若干異なるけど、下記のように記述する
let promise = new Promise(function(resolve, reject) {
// executor (生成コード, "シンガー")
});
- 下記のコードで、resolve()を呼び出すことによって、PromiseStatusはresolvedに変わって、thenの処理が実行されている
let promise = new Promise(function(resolve) {
resolve()
}).then(()=>{
console.log('resolve:成功');
});
- rejectさせて、catchの処理を確認。参考資料の「【ES6】 JavaScript初心者でもわかるPromise講座」の記事の記述がめっちゃわかりやすかった。下記の挙動をしている様、わかりやすい。
実は、catchにて実行される関数がreturnした値をresolveします。
めちゃくちゃ簡単にいうと、catchはエラー返したら満足して、解決済みだ!ってするみたいです。
つまり、catchにて返されたpromiseオブジェクトのPromiseStatusはresolveになります。
let promise = new Promise(function(resolve, reject) {
reject()
}).then(()=>{
console.log('resolve:成功');
}).catch(()=>{
console.log('reject:失敗');
});
async/awaitについて
- Promiseをasync/awaitを使うことによって、簡潔に書くことができる
asyncとは
- 非同期関数を定義する関数宣言のこと。下記のように関数の前にasyncを宣言することにより、非同期関数(async function)を定義できる
async function sample() {}
awaitとは
- async function内でPromiseの結果(resolve、reject)が返されるまで待機する(処理を一時停止する)演算子のこと。下記のように、関数の前にawaitを指定すると、その関数のPromiseの結果が返されるまで待機する
async function sample() {
const result = await sampleResolve();
// sampleResolve()のPromiseの結果が返ってくるまで以下は実行されない
console.log(result);
}
- async/await処理を追加する前
var sample = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, 1000);
});
sample.then(function(value) {
console.log("Promise成功!");
});
console.log("先に出力");
実行結果.
先に出力
Promise成功!
- 下記のように記載できる
// async function を定義
const promiseAsync = async (ms) => {
await new Promise((resolve) => {
setTimeout(() => {
resolve();
}, ms);
});
// Promiseの結果が返ってくるまで実行されない
console.log(`Promise成功!`);
};
実行結果.
先に出力
Promise成功!
- こっちの書き方もできるけど、上記の方が書き方としては簡潔に書ける
async function asyncFunction() {
var sample = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, 1000);
});
await sample; // 非同期処理が完了するのを待つ
console.log("Promise成功!");
}
asyncFunction(); // 非同期関数を呼び出す
console.log("先に出力");
まとめ
- 基本的なPromiseの書き方をまとめたものなので、何かアドバイスがあれば教えていただけますと幸いです。