Promiseには .start() .execute() が存在しない
Promise objectを作ってtaskを設置したとき、発火方法がわからなかった。
イメージとしては ↓ だったんだけど
const task = new Promise(()=>{ // task});
task.start() // こんなものはない
Promiseにそんなmethodはなかった。使えるのは6つだけ。
- Promise
.all
(promises)
- Promise
.allSettled
(promises) - Promise
.race
(promises) - Promise
.any
(promises) - Promise
.resolve
(value) - Promise
.reject
(error)
Promiseは Object を作った瞬間に start() するものだった!!
- 関数の中なら、関数が呼ばれると、Promise objectが生成される = 実行される
- MAIN関数や <script> の直下なら file loadした瞬間に Promise objectが生成される = 即実行される
発火のコントロール方法
まずPromiseの宣言方法(というか、使い方) は2つ。
- Object(変数)として作る
-
関数の中
に作る(これを個人的には関数として作る
と言いたい)
↓では最初の3つ(a, b, c)が変数、残りが関数(d, e) で書いている。
<script>
// awaitを中で使うので、この start() は async で宣言する
const start = async () => {
//////////////////////////////////////////////////////
// (a) objectだと宣言した瞬間に実行される
const objImmediately = new Promise((resolve) => {
resolve();
console.log("(a) objImmediately done");
});
// (b) objectだと宣言した瞬間に実行される
const objImmediatelyWithSleep = new Promise((resolve) => {
setTimeout(()=>{
resolve();
console.log("(b) objImmediatelyWithSleep done");
}, 400)
});
// (c) object宣言とともに実行 & awaitでこれより下の行を一時停止する
const objImmediatelyAndAwait = await new Promise(async (resolve) => {
await setTimeout(async ()=>{
resolve();
console.log("(c) objImmediatelyAndAwait done");
}, 300)
});
// (d) 関数の中で Promise objectを作る。生成即実行かと思いきや、関数が呼ばれるまでは実行されない。
const funcLater = async () => {
await new Promise(async (resolve) => {
setTimeout(()=>{
resolve();
console.log("(d) funcLater done");
}, 200)
});
}
// (e) これも関数の中なので即実行されない。Promiseをreturnすると then が使える
const funcLaterReturnPromise = async () => {
return await new Promise((resolve) => {
setTimeout(()=>{
resolve();
console.log("(e) funcLaterReturnPromise done");
}, 100)
});
}
// MAIN ////////////////////////////////////////////////////
// (a, b, c) objectは関数ではないのでできない & 不要
// objImmediately()
// objImmediatelyWithSleep()
// objImmediatelyAndAwait()
// (d) 関数を呼ぶ = promiseが初めて実行される
await funcLater();
// 返り値がないので then はできない
// await funcLater().then(()=>{console.log("then")});
// Uncaught (in promise) TypeError: Cannot read property 'then' of undefined
// (e) 返り値がpromiseだとチェーンできる
await funcLaterReturnPromise()
.then(
()=>{console.log("(e) then")
});
console.log("(f) Finished.");
}
start();
</script>
近頃は猫も杓子も promise をreturnしてくるので、async関数じゃないとコールすらできなかったりする。
(start()関数がわざわざ async function になってるのは中で awaitを使ってるから)
result
(a) objImmediately done
(c) objImmediatelyAndAwait done
(b) objImmediatelyWithSleep done
(d) funcLater done
(e) funcLaterReturnPromise done
(e) then
(f) Finished.
発火順 と 完了順
x = 発火
o = 実行中
objectの3つは宣言 即 実行されている。
関数の2つはその後で call されている。
発火順は上から下に a-e だ。
だけど、awaitが絡んで完了順は C が B を追い越している。その他は順番通り。
肝は、d&eのsleepがb&cより短いのに、d&eはb&cより後に完了する点だ。これは単純に発火を遅らせて実現している。
(c) がobjectだけどawaitしているので、(d)は (c) が終わるまで待っている。
(e) は (d) が終わるまで待っている。
まとめ
- Promise を objectとしてコールすると、即実行される。
- Promiseの発火タイミングをコントロールしたかったら、関数の中で宣言する。
関数をいつ呼ぶか
でコントロールする。
直接 new Promise してるコードを見たら その関数がいつ呼ばれたか
を知らないと即実行されたタイミングがわからない。外側の関数を見に行く必要がある。しかし大概そこでも new Promiseされている。さらに外側の関数を見に行くことになる。
僕らは無限のPromise地獄の中でもがいているのだ。