質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

859閲覧

Promise thenがうまくいかない

wergyt

総合スコア6

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2021/05/29 10:51

編集2021/05/29 12:00
function countdown(num) { return new Promise((onFulfilled, onRejected) => { for (let i = num; i >= -1; i--) { setTimeout((i) => { if (i === 13) return onRejected("この数字は不吉です"); else if (i > 0) console.log(i); else onFulfilled("Go"); }, (num - i) * 1000); } }); } countdown(3) .then((a) => console.log(a)) .catch((a) => console.error(a));

これの結果は
3
2
1
Go
となるはずですが、
Go
としかなりません。なぜですか

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lhankor_Mhy

2021/05/29 11:30

countdown の定義部分をご提示ください。 コピペミスでしょうか?
hope_mucci

2021/05/29 12:12

ご提示のコードはsyntaxerrorで動作しません。 きちんと動作するサンプルコードを提示しましょう。
hope_mucci

2021/05/29 12:15

コメントを書いている間にコードが修正されたようです。(2021.05.29 21:14) sytaxerrorはなくなりました。
guest

回答1

0

ベストアンサー

結論から言うと、setTimeout関数を実行するにあたり、

diff

1- setTimeout((i) => { 2+ setTimeout(() => { 3 if (i === 13) return onRejected("この数字は不吉です"); 4 else if (i > 0) console.log(i); 5 else onFulfilled("Go"); 6 }, (num - i) * 1000);

もしくは

diff

1 setTimeout((i) => { 2 if (i === 13) return onRejected("この数字は不吉です"); 3 else if (i > 0) console.log(i); 4 else onFulfilled("Go"); 5- }, (num - i) * 1000); 6+ }, (num - i) * 1000, i);

のどちらかの修正で期待通りの結果になります。

原因

setTimeoutのコールバック関数に引数がiついています。外側の関数にも変数iがあるので非常に紛らわしいですがこのコールバック関数中のiは外側の関数のものではなく引数のほうに束縛されています。
setTimeout関数はコールバック関数に投入する引数を第3引数以降に記載すると別途指定できます。
https://developer.mozilla.org/ja/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout
質問文のコードではコールバック関数に引数が1つ設定されているにもかかわらず、コールバック関数に渡す値が設定されていません。その場合、引数の値は undefinedとなります。
すなわち、コールバック関数内の引数iは初回実行時の時点でundefinedとなり、i === 13にもi > 0 にもマッチせず、else の文が実行され、即座にPromiseが解決されて終了、となります。

前者の修正の場合

コールバック関数の引数を削除しています。
この場合、コールバック関数内の変数iは外側の関数の変数iに束縛されますが、この場合、setTimeout関数コール時点のiの中身で束縛されることになります。
厳密には異なりますが、外側関数の変数iの値でコールバック関数内のiがリテラルのように書き換わるような動作になります。
なので、それぞれiが3,2,1,0 に置き換わったコールバック関数がスタンバイされることになります。
この場合は、期待通り 3 2 1 Goと出力されます。

後者の修正の場合

先述したように、ちゃんとコールバック関数に渡す引数の値をdelay値に続いて記載することでiundefinedなることを防止できます。
この場合、コールバック関数内引数の変数名は外側のブロックと同じものを使わないようにすべきです。非常に紛らわしく、too bad なコードです。

投稿2021/05/29 12:58

hope_mucci

総合スコア4447

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問