🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
JavaScript

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

Q&A

解決済

4回答

790閲覧

JavaScriptのPromiseとAsyncについての質問

tailer

総合スコア62

JavaScript

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

1グッド

2クリップ

投稿2019/11/18 03:20

Qiitaの以下の記事を読みながらAsyncについて学習していました。
https://qiita.com/toshihirock/items/e49b66f8685a8510bd76

記事の中ではこのようなコードが登場します。

javascript

1function sampleResolve(value) { 2 return new Promise(resolve => { 3 setTimeout(() => { 4 resolve(value); 5 }, 2000); 6 }); 7} 8 9function sampleResolve2(value) { 10 return new Promise(resolve => { 11 setTimeout(() => { 12 resolve(value * 2); 13 }, 1000); 14 }); 15} 16 17async function sample() { 18 const [a, b] = await Promise.all([sampleResolve(5), sampleResolve(10)]); 19 const c = await sampleResolve2(b); 20 21 return [a, b, c]; 22} 23 24sample().then(([a, b, c]) => { 25 console.log(a, b, c); // => 5 10 20 26});

そこで疑問です。
sampleResolve関数sampleResolve2関数はPremise型を返す関数として定義されていますが、この二つの関数をAsyncで書き直すことはできるのでしょうか?

以下は上手く動作しませんがこのようなイメージです^^;

Jacascript

1function sampleResolve(value) { 2 async = () => { 3 setTimeout(() => { 4 return(value); 5 }, 2000); 6 } 7}

初心者の私からするとAsyncとPromiseが入り混じっていてどちらかに統一したい気持ちになります。私自身の理解が浅く申し訳ありませんが、ご教授いただけますと幸いです。

jun68ykt👍を押しています

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

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

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

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

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

guest

回答4

0

ベストアンサー

意図は

『setTimeout を使って、async 関数を止めたい』

だと思っています。

sampleResolve 関数と sampleResolve2 関数は
Premise 型を返す関数として定義されていますが、
この二つの関数をAsyncで書き直すことはできるのでしょうか?

結論

残念ながら、できません。

理由

setTimeout は Promise 型のオブジェクトを返さないからです。

async 関数は、await 文を使って止めることができます(処理が完了するのを待つことができます)。
なぜなら async 関数は Promise 型のオブジェクトを返してくれるからです。

ここで大事なのは
await 文で止めることができるのは Promise 型のオブジェクトだけ
だと言うことです。

問題

setTimeout 関数が返すオブジェクトの型は、次のうちどれですか?

  1. Undefined 型のオブジェクト
  2. Promise 型のオブジェクト
  3. Number 型のオブジェクト

以下のコードをコンソールにコピペして実行したとき...

js

1async function main() { 2 let start, end 3 4 start = Date.now() 5 await f() 6 end = Date.now() 7 console.log(end - start) // <--- 実行結果 1 8 9 start = Date.now() 10 await g() 11 end = Date.now() 12 console.log(end - start) // <--- 実行結果 2 13} 14 15async function f() { 16 await sleep(1000) 17 await sleep(1000) 18 await sleep(1000) 19} 20 21async function g() { 22 const promise0 = sleep(1000); 23 const promise1 = sleep(1000); 24 const promise2 = sleep(1000); 25 await promise0; 26 await promise1; 27 await promise2; 28} 29 30function sleep(time) { 31 return new Promise((resolve, reject) => { 32 setTimeout(() => { 33 resolve() 34 }, time) 35 }) 36} 37 38main()

console.log の実行結果 1, 2 に表示される組み合わせとして
もっとも近いものは、次のうちどれですか?
なお表示される結果は完全には、一致しません。だいたいの値です。

選択肢実行結果 1実行結果 2
110001000
210003000
330001000
430003000

解答

正解は 3 番です。
setTimeout は Promise 型のオブジェクトを返しません。
なので await 文で止めることができません。

javascript

1const type = (object) => Object.prototype.toString.call(object).slice(8, -1) 2type(setTimeout(()=>{}, 0))
> type(setTimeout(()=>{}, 0)) "Number" >

正解は 3 番です。

補足

① Promise は setTimeout で主に使い、他ではあまり使わない

らしいです。以下の記事がとても勉強になります。

ただ、new Promise(...)と、Promiseの前にnewを付ける書き方も、
最後にコールバックを受け取る関数以外(setTimeoutとか)を扱う以外は
基本的に使うことはほとんどないでしょう。
イマドキのJavaScriptの書き方2018 - Qiita

② sleep の実装

async 関数を止める sleep させるような処理を以下のような具合で書けるらしいです。
個人的に勉強になったので付記しておきます。

javascript

1const sleep = () => new Promise(resolve => setTimeout(resolve, 3000))

まとめ

async 関数の中で、非同期処理を途中で止めることができるのは await 文だけです。
await 文で、止められるのは Promise 型のオブジェクトだけです。

setTimeout は
Promise 型のオブジェクトを返さず Number 型のオブジェクトを返します。
そのため await 文で処理を止めることができず、突き抜けていってしまいます。

投稿2019/11/18 03:41

編集2019/11/19 06:56
nico25

総合スコア830

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

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

tailer

2019/11/18 16:08

わかりやすく解説していただきありがとうございました。大変勉強になりました。
miyabi_takatsuk

2019/11/19 03:43 編集

横槍すみません。 setTimeoutが返すのはundefinedではありません。 https://developer.mozilla.org/ja/docs/Web/API/WindowTimers/setTimeout ブラウザにおいては、 timeoutID(一意のnumber型の値)を返します。 Node.jsでは別のものを返すようで、プラットホームによって違うようですが、undefinedを返す環境はないかと思います。 これは、crearTimeoutを実行する際に返ってきた値を引数にいれ、止めたいsetTimeoutを特定するためでしょう。
nico25

2019/11/19 05:51

ご指摘いただき、なぜそのようになっているのかまで教えていただき、ありがとうございます。 早々にさせて修正させていただきます。
guest

0

sampleResolve関数とsampleResolve2関数はPremise型を返す関数として定義されていますが、この二つの関数をAsyncで書き直すことはできるのでしょうか?

できません。
書き直しできるかどうかを見極めるポイントは、関数を抜けるタイミングです。

Promiseの定義を略記できる構文が async 関数ではありますが、関数の実装によっては略記できないケースもあり、ご質問の2つの関数が正にそのケースに該当します。

asyncFunction は throw せずに関数を抜けると resolve() が実行されたものとして Promise の結果を返します。

sampleResolve(), sampleResolve2() では、ともに setTimeout の第一引数に与えられた関数よって resolve() されるので、関数を抜けても待つ必要があります。

これを asyncFunction に書き換えたら、

  • 意図したsetTimeout内の resolve() が実行される前に、
  • asyncFunctionを終えて return される(意図しない)値で resolve() が実行されます。

略記できるメリットは、Promiseによるフロー制御を活用した NodeJS のミドルウェアフレームワーク(KoaJS)が参考になります。


追記)

このようなイメージです^^;

の次に記述されているコードは丁度 sleep 関数であろうと察します。
nico25 さんの回答を参考にしてください。

ごめんなさい。勘違いでした。

投稿2019/11/18 05:24

編集2019/11/18 05:56
AkitoshiManabe

総合スコア5434

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

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

tailer

2019/11/18 16:10

> 書き直しできるかどうかを見極めるポイントは、関数を抜けるタイミングです。 この説明で納得できました。感謝いたします。
sasnight

2019/11/18 20:09

高評価しました。これはより正確な説明だと思います。
guest

0

初心者の私からするとAsyncとPromiseが入り混じっていてどちらかに統一したい気持ちになります。

残念ながら、もともとPromiseを返さない処理をasync-awaitに乗せるには、いったんPromiseを作成するプロセスを経る必要があります。

投稿2019/11/18 04:13

maisumakun

総合スコア145965

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

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

0

ちょっと何をしたいかわかりません
async指定するとpromiseを返すことはご理解されていますか?
逆にasyncしてもリゾルバが実行されないと処理が続かない場合あります。
setTimeoutはawaitで止められないので結局promiseでリゾルバを発行することになります

javascript

1const sampleResolve=async value=>{ 2 await new Promise(resolve=>{ 3 setTimeout(() => { 4 resolve(); 5 }, 2000); 6 }); 7 return value 8}; 9 10const sampleResolve2=async value=>{ 11 await new Promise(resolve=>{ 12 setTimeout(() => { 13 resolve(); 14 }, 1000); 15 }); 16 return value * 2; 17} 18 19const sample=async()=>{ 20 const [a, b] = await Promise.all([sampleResolve(5), sampleResolve(10)]); 21 const c = await sampleResolve2(b); 22 23 return [a, b, c]; 24} 25 26sample().then(([a, b, c]) => { 27 console.log(a, b, c); // => 5 10 20 28});

投稿2019/11/18 03:43

yambejp

総合スコア116661

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問