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

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

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

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

Q&A

解決済

3回答

623閲覧

async function/await/promiseの動きがわからない

退会済みユーザー

退会済みユーザー

総合スコア0

JavaScript

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

0グッド

2クリップ

投稿2018/07/19 03:46

編集2018/07/19 05:40

発生している問題

お世話になります。
async function/await/promiseの実行される順番がよくわからないので教えてください。

  1. なぜ1 5と行かないでasync functionの中に入っていくのですか?(No.1/No.2)
  2. なぜawaitがあるとasync functionの外に行くのですか?(No.1)
  3. なぜ2 4と行かないで2 3 4と表示されるのですか?(No.2)

該当のソースコード

javascript

1function pro(){ 2 return new Promise((res)=>{ 3 console.log(3); 4 res(); 5 }); 6} 7 8// No.1 9console.log(1); 10(async function(){ 11 console.log(2); 12 await pro(); 13 console.log(4); 14})(); 15console.log(5); 16// 1 2 3 5 4 17 18// No.2 19console.log(1); 20(async function(){ 21 console.log(2); 22 pro(); 23 console.log(4); 24})(); 25console.log(5); 26// 1 2 3 4 5

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

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

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

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

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

m.ts10806

2018/07/19 04:00

質問編集画面タイトル横にある「初心者アイコン」をご活用ください。「初心者」と質問で書くよりも伝わりますし、質問一覧に表示されるのでわかりやすくなります。
退会済みユーザー

退会済みユーザー

2018/07/19 05:41

アドバイスありがとうございます!承知致しました。
guest

回答3

0

ベストアンサー

async付きの関数は、本質的には**Promiseを返す関数**です。awaitなしで呼べばPromiseを受け取ることもできますし、逆にasync表記でない、返り値がPromiseの関数をawaitさせることもできます。

そして、async-awaitの仕様を読み解いてみると、awaitが現れるまでの間は同期的に実行されることとなります。簡単に言えば、await以降の行を、awaitで待つPromise.then()に切り出したような感じになります。

つまり、

なぜ1 5と行かないでasync functionの中に入っていくのですか?(No.1/No.2)

async関数といってもawaitまでは同期的に実行されるからです。

なぜawaitがあるとasync functionの外に行くのですか?(No.1)

async 式と書いた場合も、「式」を評価してからそこにthenをぶら下げる、というような感じで処理が進みます。

なぜ2 4と行かないで2 3 4と表示されるのですか?(No.2)

どこでもawaitしていないのですべてが同期的に進んでいます(proで生成したPromiseもただ捨てられています)。

投稿2018/07/19 04:29

編集2018/07/19 04:32
maisumakun

総合スコア145121

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

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

退会済みユーザー

退会済みユーザー

2018/07/19 23:06

回答ありがとうございます。 大変参考になりました!
guest

0

修正というか正しい非同期処理とその同期的処理

お二方から指摘がありますが、 pro() は呼び出した瞬間同期的に console.log(3) が実行されます。
というのも Promise を生成してますが引数に与えられたコールバック関数の中でいきなり console.log(3) としているからですね。
例えば 3 秒待った後に 3 と出力 するような非同期関をコールバック関数として引数に与えるのならば以下のようになります。

const output3 = () => new Promise(resolve => { setTimeout(() => { console.log('3'); resolve(); }, 3000) });

そして以下のコードを試してみてください。

output3(); console.log(2); console.log(1);

3 2 1 と出力されそうですが、実際は 2 1 3 となります。

というのも output3 が Promise を返す非同期処理だからですね。
output3 の Promise の処理が完了していることを期待して、 次の console.log() を実行するには await キーワードを使用して、 Promise の完了を待つ必要があります。
しかし、 await キーワードは async function の中でしか使えないという制約があるので以下のようにします。
(トップレベル await が可能な仕組みが現在作られています。ちなみに GoogleChrome の デベロッパーコンソールもトップレベル await が可能)

async function() { await output3(); console.log(2); console.log(1); }

関数宣言しただけでは動かないので即時呼び出しする(即時関数)

(async function() { await output3(); console.log(2); console.log(1); })();

これを実行すると、めでたく 3秒待って 3が出力され、続いて 2, 1 となります。????


なぜ1 5と行かないでasync functionの中に入っていくのですか?(No.1/No.2)

即時関数だから。さらに async function なので 2 の次に 5 が来るか、 3 が来るかは保証できません。

なぜawaitがあるとasync functionの外に行くのですか?(No.1)

外へ行ってません。 関数 pro を呼び出しているだけ。

なぜ2 4と行かないで2 3 4と表示されるのですか?(No.2)

これは例が悪いですね。 pro() がもっと時間のかかる処理なら 1 2 4 5 3 となりそうですが、すぐ終わる処理なので順当に 1 2 3 4 5 となりました。これも async function なので 2 の後が 5 なのか 3 なのかは保証できません。


別に珍しい質問ではないし既に先人が抱いてきた疑問なので 非同期処理 で調べればいくらでも詳しい説明は出てきそうですけどね。それをこの場で説明してくださいというのは、何も調べていないということではないでしょうか。

投稿2018/07/19 04:27

編集2018/07/19 06:41
og24715

総合スコア832

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

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

maisumakun

2018/07/19 04:37 編集

自分が別に回答しましたが、この場合1つ目でも「1 の次に 5 が来る」ようなことは起きません。「asyncなのに同期的に動く」ということのほうがこの疑問に対する回答のような気がします。
og24715

2018/07/19 04:43

ああ、そうでした。正しくは 2 の後に、 5 か 3 ですね訂正します。 > 「asyncなのに同期的に動く」ということのほうがこの疑問に対する回答 これちょっとわからないです。どういうことでしょうか。
maisumakun

2018/07/19 04:46

自分の回答をお読みください。async functionでも、await以前(awaitがなければ全体)は同期的に実行されます。
og24715

2018/07/19 05:34 編集

んーすみません。今の回答で間違っている箇所があれば引用で直接指摘していただけると自分の誤解もあるかと思うので認識のズレをなくせると思うのですが、もしかして、"1 の次に 5 が来る" ことについておっしゃらてます?もしそうであれば訂正したのでご勘弁ください。 それとも async function の中身と外の console.log() が同期的に処理されるという主張ですか?
maisumakun

2018/07/19 05:39

>「async function なので 2 の次に 5 が来るか、 3 が来るかは保証できません。 」 new Promiseに渡したコールバック自体も同期実行なので、2の次は3で確定です。 >「これも async function なので 2 の後が 5 なのか 3 なのかは保証できません。」 async functionですが、awaitがないので同期的に実行され、さらにnew Promiseに渡したコールバック自体も同期実行なので、1→2→3→4→5に決まります。
og24715

2018/07/19 05:54

あーー!なるほど。自分で勝手な前提を作ってました。コレばっかりは申し訳ないです。 質問者の提示のコード中の pro 関数が Promise 返してるけどなんの非同期処理もせずいきなり console.log() 吐いてるんですよね。これを勝手に読み替えて何かしらの重い処理をした後に resolve で 3 を返すと解釈してました。 つまりはログを追っかけるだけなら pro 関数 は `() => console.log(3)` と等価なんですよね。 maisumakun さんの回答の通り async function は Promise を返すから中と外は非同期だから注意してねって主張をしたかったんですが、質問者提示中の pro() を尊重するのであれば 私の回答は完全に間違いですね。
退会済みユーザー

退会済みユーザー

2018/07/19 06:15

回答ありがとうございます! みなさんが通ってきた道だと聞いてなんだか安心しました。 自分の努力が足りず申し訳ありませんでした。 なんとか乗り越えます!
guest

0

現象としてはmaisumakunさんや、og24715さんが挙げたのが理由かと思いますが、
基本的にPromiseを返すようなライブラリやモジュールってのは、
速攻で別のページにAjaxでアクセスしにいったり、FileAPIで読み書きしたり…といった風に非同期的に行われるものだからです。

なので直感的に思い描いてた動作とは違う事になっていますが、
理屈は単純で、実際に非同期の処理で切り離されるまで、全ての同期処理を面倒見るからです。
サンプルコードはPromiseを使いこそはしていますが、中身は全て同期的な処理なので全て面倒をみている事がわかります。

await pro()の下のconsole.log(4)が遅延しているのは、
awaitという糖衣構文によりpro().then(() => { console.log(4) })を見てくれだけ修正しているからです。

もしpro関数内部でsetTimeout等を使って0ms後に発火する非同期処理を経由するよう修正すれば、
思い描いていた挙動に近づけるかと思います。

投稿2018/07/19 05:48

miyabi-sun

総合スコア21158

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

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

maisumakun

2018/07/19 05:53

「awaitなしのasync function」なんてのも成立するんですね…何に使えばいいかよくわからないですが。
miyabi-sun

2018/07/19 06:31

async関数は単に中身を`return new Promise(fn)`でまるっと囲んだ関数の糖衣構文なので、 「awaitなしのasync function」は成立しますよ。 単純に他の人にawait付きで実行してもらう為の関数宣言ですね。
退会済みユーザー

退会済みユーザー

2018/07/19 23:11 編集

回答ありがとうございます。 これを参考にもっと探求します!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問