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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

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

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Q&A

解決済

2回答

746閲覧

node.jsのasync、awaitについて

tama-

総合スコア16

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

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

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

0グッド

0クリップ

投稿2019/03/25 03:27

現在node.jsにて非同期処理について学んでいますが、async、awaitがうまく理解できません。。。

js

1async function test() { 2 const log2 = async() => { 3 return setTimeout(() => { 4 console.log(2); 5 }, 1000); 6 }; 7 8 console.log(1); 9 await log2(); 10 console.log(3); 11}

上記のtest()を実行すると、
個人的には↓の出力になると思っていました。
1
2
3 ※awaitでlog2の処理を待ってconsole.log(3)が実行されると予想

ですが、実際の処理結果は↓になりました。
1
3
2

awaitが効いていない(?)のはどのような原因になるのでしょうか。

調べても中々理解できないため、お教えいただければ幸いです。。。

よろしくお願いしますm(_ _)m

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

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

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

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

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

guest

回答2

0

ベストアンサー

まずasync-awaitはproimiseのシンタックスシュガーに過ぎず、
promiseを理解されていないと使えません。

promiseは簡単に言えば既存のコールバック関数による非同期処理をオブジェクトとして纏めたものです。
promise自体を理解していないとasync-awaitは使えません。

promiseに関しては以下が勉強になります。
http://azu.github.io/promises-book/

そして間違えているのが、setTimeout です。
setTimeoutは既存のコールバック関数による非同期処理 なので、promiseに変換して上げる必要があります。

const setTimeoutPromise = (ms) => new Promise(resolve => setTimeout(resolve, ms));

上記を踏まえて書くと

const setTimeoutPromise = (ms) => new Promise(resolve => setTimeout(resolve, ms)); async function test() { const log2 = async() => { await setTimeoutPromise(1000) console.log(2); }; console.log(1); await log2(); console.log(3); } test();

投稿2019/03/25 03:54

m0a

総合スコア708

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

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

tama-

2019/03/25 04:00

リンク先、実装例のご用意と至れり尽くせりでありがとうございます!!! promiseについてリンク先を覗いて学ぼうと思いますm(_ _)m 大変助かりました!
guest

0

async/awaitはPromiseの糖衣構文です。
結論から言えば質問文のコードは動かなくて当然なので、
まずはぐっと我慢してPromiseという非同期処理の仕組みを勉強してください。

Promiseの仕組みさえ理解していれば、
こんな感じで解決することが出来るようになります。

JavaScript

1async function test() { 2 const log2 = () => new Promise(resolve => 3 setTimeout(() => resolve(2), 1000) 4 ); 5 console.log(1); 6 console.log(await log2()); 7 console.log(3); 8} 9test(); 10// 1 11// 2 <- 1秒程待ってから出力 12// 3 <- 2の後に出力

とはいえ、無策でPromise - MDNへ突撃しても泣かされて帰ってくるのがオチなので、
多少アドバイスしておきます。

まず元祖非同期処理に関して

JavaScriptはシングルスレッドなので並列実行が出来ません。
なのでイベント駆動という概念が存在しています。

イベント置き場に、「イベント発火条件」と「実行して欲しい関数」とセットで登録し、
処理自体は速攻で終わります。
その後、イベントループという巡回が始まり、イベント発火条件を満たした関数を1つずつ取り出して順次実行していくという流れになっています。
(他にもイベントループより優先して実行する割り込み的なルールも存在しますが割愛)

setTimeout(fn, 1000)がその代表的な例です。
「1000ミリ秒経過したら、併設の関数を実行しなさい」

明確ですね。
実際にはイベントループでの巡回を経てから実行に移す為、
1000ミリ秒きっかりで実行するのではなく、数ミリ秒の誤差が生じます。

これによりシングルスレッドでありながら、遅延や並列処理を手にする事に成功しました。
しかし、関数の中にやりたいことを全部書けとは中々クレイジーですね。
関数を無限に挟み込む事になってしまいます。

この関数定義で無限にコードがネストしていく事を「コールバック地獄」と呼びます。

Promiseの説明

Promiseとはコールバック地獄を解決する目的で作られた、
オブジェクト指向のデザインパターンのようなものです。

Promise式の非同期処理の関数を実行した場合、
即刻Promiseオブジェクトのインスタンスが帰ってきます。

このPromiseオブジェクトは今何かしらの処理を実行しているから「待っていてね」を示すPending状態になっており、
実行が完了して状態が正常終了(fulfilled)になった場合完了を表します。

Promiseインスタンスには.then(fn)メソッドが用意されており、
完了次第実行して欲しい内容を関数で包んで.then(fn)で登録しておけば、
Promiseの状態が正常終了(fulfilled)になった瞬間に関数を実行してくれます。

なーんだ非同期のコールバック地獄と同じじゃん、何が嬉しいの?
それは。then(fn)の中身の関数がPromiseを返すようにしておけば、
.then(fn).then(fn)とメソッドチェーンでコードを記述出来るということです。

これにより、やってることは実質変わらないけど、
コールバック地獄の無限ネストを1段階のネストで抑え込む事が可能になりました。
質問文をPromiseでやるとこんな感じのコードになります。

JavaScript

1function test() { 2 console.log(1); 3 new Promise(resolve => 4 setTimeout(() => resolve(2), 1000) 5 ).then(value => { 6 console.log(value); 7 console.log(3); 8 }) 9} 10test(); 11// 1 12// 2 <- 1秒後に出力 13// 3 <- 2の直後に出力

async/await構文とのつながり

先程async/awaitはPromiseの糖衣構文と記載しました。

async構文で作った関数は、絶対Promiseインスタンス返すマンみたいな挙動で、
return valueをPromiseのコンストラクタの引数resolve関数を実行するのと同じ挙動をします。
それとは別にawait構文がasync関数の中身で使用可能になります。

await構文は右辺のPromise完了を一生待ちます。
実行が完了したと想定して後続のコードを全て.then(fn)で包んだ挙動として宣言します。
これにより一見非同期のコードを動的にプログラミング出来ているといった形になります。

詳しい内容はMDNのサイトを見てください。

投稿2019/03/25 04:16

miyabi-sun

総合スコア21158

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

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

tama-

2019/03/25 08:22

とても詳しい説明ありがとうございます!!! MDNを呼んでも中々理解ができなかったのですが、miyabi-sunのご説明のおかげで感覚つかめたと思います! こちらもベストアンサーにしたいです! 大変助かりました!!! 頂いた内容を参考に勉強し直しますm(_ _)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問