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

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

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

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

Q&A

解決済

3回答

644閲覧

JavaScriptでカウントダウンをする際に、カウントダウンが終わるまで処理を待ちたい。

Okt

総合スコア21

JavaScript

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

0グッド

0クリップ

投稿2023/07/19 15:27

実現したいこと

JavaScriptで、カウントダウンを表示し、その後になって処理を実行したい。

前提

JavaScriptのasync、awaitを使ってカウントダウンを実現するとことまでは来ましたが、このカウントダウンを実行中でもプログラムは次に進んで処理を実行してしまいます(当たり前ですが、、、)。
実現したいのは、consoloe.log("end")というのが、カウントダウン後に実行させることです。

発生している問題・エラーメッセージ

あえて非同期処理をせず、最後のconsole.logの実行を待たせておきたいのですが、やり方が分かりません。

該当のソースコード

HTML

1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <link rel="stylesheet" href="style.css"> 7 <title>Document</title> 8</head> 9<body> 10 <div class="box"> 11 <p class="num"></p> 12 </div> 13 <script src="main.js"></script> 14</body> 15</html>

CSS

1* { 2 margin: 0; 3 padding: 0; 4 box-sizing: border-box; 5} 6 7.box { 8 width: 500px; 9 height: 500px; 10 background-color: rgb(254, 243, 230); 11 position: relative; 12 top: 100px; 13 left: 100px; 14 display: grid; 15 place-items: center; 16} 17.box .num { 18 width: 450px; 19 height: 450px; 20 text-align: center; 21 line-height: 450px; 22 font-size: 400px; 23}/*# sourceMappingURL=style.css.map */

JavaScript

1const box = document.querySelector(".box"); 2const num = document.querySelector(".num"); 3 4const cnt_down = async(val) => { 5 for(let i = val; i >= 0; i--) { 6 await print(i); 7 } 8}; 9 10const print = (val) => { 11 return new Promise(res => { 12 setTimeout(function() { 13 num.textContent = val; 14 res(); 15 },1000); 16 }); 17} 18 19console.log("start"); 20 21cnt_down(5); 22 23console.log("end"); 24

どなたか、よろしくお願いいたします。

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

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

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

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

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

guest

回答3

0

全体の挙動をasyncにすればいいのでは?

javascript

1<script> 2window.addEventListener('DOMContentLoaded', async()=>{ 3 const box = document.querySelector(".box"); 4 const num = document.querySelector(".num"); 5 const cnt_down = async(val) => { 6 for(let i = val; i >= 0; i--) { 7 await print(i); 8 } 9 }; 10 const print = (val) => { 11 return new Promise(res => { 12 setTimeout(()=>{ 13 num.textContent = val; 14 res(); 15 },1000); 16 }); 17 } 18 console.log("start"); 19 await cnt_down(5); 20 console.log("end"); 21}); 22</script> 23<div class="box"> 24<p class="num"></p> 25</div>

参考

async/awaitがいやなら予めスケジューリングしてpromise.allしてもよいかも

javascript

1<div class="box"> 2<p class="num"></p> 3</div> 4<script> 5const box = document.querySelector(".box"); 6const num = document.querySelector(".num"); 7const start_num=5; 8const end_num=0; 9const print =(v,w)=>wait(w).then(x=>num.textContent=v); 10const wait = (sec) =>new Promise(resolve =>setTimeout(resolve,sec*1000)); 11console.log("start"); 12Promise.all([...Array(start_num - end_num+1)].map((_,i)=>i).map(x=>print(start_num-x,x))).then(()=>console.log("end")); 13</script>

投稿2023/07/20 00:09

編集2023/07/21 06:29
yambejp

総合スコア115334

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

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

Okt

2023/07/22 04:19

ありがとうございます。 ちょっと調べて勉強してみます。 また何か質問するかもしれません!!!
Okt

2023/07/22 07:10

すみません、、、 promise.allのことについては検索しながら何となくわかりました。複数あるpromiseのすべてがfullfilledになった時に、allのfullfilledを返す、という認識で良いと思うのですが、 今回書いていただいたコードの、このpromise.allの中でどんな処理をしているのか、初学者である私にはまったく読み解けません、、、 ざっくりとで構いませんのでどんな処理が行われているのか教えていただけると幸いですm(__)mm(__)m
guest

0

ベストアンサー

思いつくのは2通りです。

javascript

1console.log("start"); 2 3cnt_down(5); 4 5console.log("end");

の部分を以下の 1. または 2. のように修正します。

1.cnt_down(5) の返すPromise のthenメソッドを使い、引数に渡すコールバックの中で"end"のログ出力を行う。

javascript

1console.log("start"); 2 3cnt_down(5).then(() => { 4 console.log("end"); 5}); 6
2. 「"start"ログ出力・cnt_down(5)・"end"ログ出力」を実行する async な即時実行関数式を作成して即実行する。この中でcnt_down(5) の終了をawait で待つ。

javascript

1(async () => { 2 console.log("start"); 3 4 await cnt_down(5); 5 6 console.log("end"); 7})();

補足

もうひとつ、質問にある元のコードとかなり違ってしまいますが for await...of を使ってみる案です。

javascript

1const box = document.querySelector(".box"); 2const num = document.querySelector(".num"); 3 4async function* valueGenerator(value, timeout=1000) { 5 while (value > 0) { 6 await new Promise(resolve => setTimeout(resolve, timeout)); 7 yield value; 8 value --; 9 } 10} 11 12(async () => { 13 console.log("start"); 14 15 for await (const v of valueGenerator(5)) { 16 num.textContent = v; 17 } 18 19 console.log("end"); 20})(); 21 22

投稿2023/07/19 19:41

編集2023/07/19 20:23
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Okt

2023/07/20 07:39

回答ありがとうございます!!! 初学者ながら、ググりながら勉強してみました。 ジェネレーターの方で、1秒ごとにresolveでGOサインを出し、値が産出されることはわかりました。そして、その値が出るたびにfor ofを使って値を実際に書き入れていく際に、なぜこちらの方の関数にも「async」「await」が必要なのでしょうか? いわば書き出し役のこのfor ofの方でも、ジェネレーターが数字を返してくるのを待っている(awaitする)必要があるのですか?それとも、「async」関数を呼び出す際にはルールとして呼び出す側の関数も「async」でなければならないのですか? お手すきであれば、ご教示お願い致します。m(__)mm(__)m
退会済みユーザー

退会済みユーザー

2023/07/20 10:38

コメントありがとうございます。 コメントに書いてある中では > 「async」関数を呼び出す際にはルールとして呼び出す側の関数も「async」でなければならない という考え方が、非同期処理を扱うための正しい理解に "近い" です。 "近い" という意味は、より正確には 「async」関数を await 付きで呼び出しその関数の返すPromiseがresolveされるかreject されるかまで待つ際にはルールとして呼び出す側の関数も「async」でなければならない という理解がより正しい(というのが私の理解)です。 本題のfor await...of 構文についてですが、 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for-await...of の「解説」の中に ・for await...of は await が使えるコンテキストでのみ使用できます。 という一文があります。「await が使えるコンテキスト」とは、先ほどの理解の仕方: 「async」関数を await 付きで呼び出しその関数の返すPromiseがresolveされるかreject されるかまで待つ際にはルールとして呼び出す側の関数も「async」でなければならない で言えば、"呼び出す側の関数" 本体の中を表しますので、for await...of もまた async な関数の中でのみ使える ということになります。 実際、 (async () => { console.log("start"); for await (const v of valueGenerator(5)) { num.textContent = v; } console.log("end"); })(); において "await が使えるコンテキスト" を作り出している非同期の即時実行関数を削除して単に console.log("start"); for await (const v of valueGenerator(5)) { num.textContent = v; } console.log("end"); とするとエラーになり意図通り動かないと思います。
Okt

2023/07/21 06:04

ありがとうございます。 >「async」関数を await 付きで呼び出しその関数の返すPromiseがresolveされるかreject されるかまで待つ際にはルールとして呼び出す側の関数も「async」でなければならない これでよく理解できました。 そして、「for await...of 構文」という構文として存在するですね。またひとつ勉強になりました。ありがとうございました!!!!!
退会済みユーザー

退会済みユーザー

2023/07/21 07:20

コメントありがとうございます。 > ・・・ これでよく理解できました。 とのことでよかったです👏 最後にもうひとつだけ補足しますと、実はその > これ には例外があります。 Javascriptでサーバーシステムを作るときなど Node.js を使いますが、最近のNodeでのjavascript だと 最上部のスコープ(=何の関数の内部にも入ってない範囲)で、await を使えます。 これを「トップレベル await」 と言います。 参考: https://zenn.dev/estra/books/js-async-promise-chain-event-loop/viewer/16-epasync-top-level-async ただし上記の例外は、質問にあるコードのようなWEBブラウザで動かすJavascript でフロントエンド開発をしている分にはいったん忘れてしまっておいても問題ありません。
guest

0

awaitは非同期関数でしか利用できないので、別途非同期関数を定義するような形になるかと思います。

javascript

1const box = document.querySelector(".box"); 2const num = document.querySelector(".num"); 3 4const cnt_down = async(val) => { 5 for(let i = val; i >= 0; i--) { 6 await print(i); 7 } 8}; 9 10const print = (val) => { 11 return new Promise(res => { 12 setTimeout(function() { 13 num.textContent = val; 14 res(); 15 },1000); 16 }); 17} 18 19// 非同期関数の定義 20const do_cnt_down_5sec = async() => { 21 console.log("start"); 22 23 await cnt_down(5); 24 25 console.log("end"); 26} 27 28// 定義した関数の実行 29do_cnt_down_5sec(); 30

投稿2023/07/19 16:05

Eggpan

総合スコア2946

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.43%

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

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

質問する

関連した質問