javascriptのPromiseの実行順序が分からない
解決済
回答 2
投稿
- 評価
- クリップ 4
- VIEW 1,998
前提・実現したいこと
現在、JavaScriptの非同期処理を理解する必要があるため
- コールバック
- Promise
- async/await
について勉強していました。
しかし、Promiseの挙動について不可解な点があります。
発生している問題
function asyncFunc(val) {
console.log("first");
return new Promise((resolve, reject) => {
console.log("second");
resolve(val * 2);
})
}
asyncFunc(50)
.then((val) => {
console.log(val);
});
console.log('here');
以上のコードをブラウザで実行したときに、実行順序が
first
second
here
100
のようになります。
個人的には、
first
here
second
100
の順番で出力されると考えていました。
上記のような順番であると考える理由
JavaScriptの勉強内で
ChromeのようなWebブラウザは
v8(ブラウザ内のjs実行エンジン)
- シングルスレッド
- スタック(関数・処理を積んでいく)
Web API
- DOM
- Timer
- setTimeout
キュー
- もしv8のスタックが空なら、非同期処理が終わった部分をスタックに戻す
という3構成であると考えていました。
例えば、setTimeout(f)を実行すると
まずスタックに入り
その後setTimeoutなので、Web APIだ! とブラウザが代わりに実行して(タイマーを測って)
そして、タイマーの時間になったら、キューに移し、スタックが空いている瞬間があったらfをスタックに入れて実行する。
という認識です。
そのため、上記のコードを実行すると
asyncFuncをスタックに積む
asyncFuncを解析すると、console.log("first")があるので実行する。
return new Promiseなので、WebAPIもしくはキューに中身を打ち込む。
(Promiseは、resolve, rejectがなされるまで内部状態が変わらないので、おそらくWebAPI・キューに積まれる)console.log("here")を実行する。
スタックが空いたので、Promise内を実行し、まずsecondを出力する。
resolveを実行し、FulFilled状態になりthenメソッドが呼ばれる。
thenメソッド内のconsole.log(val)をスタックに積んで実行する。
という流れになると想定していました。
しかし、実際の実行順序は
thenメソッドだけが後回しでそれ以外が先に実行されていました。
これはどういう実行順序、またはPromiseの仕組みなのでしょうか?
よろしくお願いいたします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+4
これはどういう実行順序、またはPromiseの仕組みなのでしょうか?
よくある勘違いですが、new Promise
の引数に渡した関数は同期的に実行されます。
executor
関数(引用者注:new Promise
の引数となる関数)はresolve
関数とreject
関数が渡されてPromise
が実装されるとすぐに実行されます (Promise
コンストラクターがオブジェクトを返すよりも前にexecutor
は実行されます)。 ―MDNより
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
asyncFuncがasyncになっていなからでは?
async function asyncFunc(val) {
await console.log("first");
return new Promise((resolve, reject) => {
console.log("second");
resolve(val * 2);
});
}
全体をちゃんと書くと
const asyncFunc=async val=>{
await console.log("first");
return new Promise(resolve=>{
console.log("second");
resolve(val * 2);
});
};
asyncFunc(50).then(console.log);
console.log('here');
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.23%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2019/09/11 16:57
上記のコードでは
console.log("second")はすぐに実行されて
**resolve(val*2)**のみが、キューに積まれるのでしょうか?
また、同期的に実行するということは、Promiseは正確には非同期処理ではないのでしょうか?
2019/09/11 17:02 編集
いえ、このコードの場合、resolveも同期的に実行されます。.thenに与えた関数は(同期的にresolveされようが)常に非同期実行となるようになっています。
> また、同期的に実行するということは、Promiseは正確には非同期処理ではないのでしょうか?
new Promise()に与える関数は、Promiseの初期化用です。非同期実行が始まる前の段階です。
2019/09/11 17:35
Promise内はすべて基本的には同期処理で、
thenやcatchのみが非同期に実行される。
よって、then()内のconsole.log(val)のみが最後に実行されて
その前にconsole.log(here)が実行されている
というのであっていますでしょうか?