実現したいこと
プログラムを実行すると
func1()が実行されました。 func2()が実行されました。i = 100000000 func3()が実行されました。
となります。func2()関数は処理内容が多いので、遅れて出力されるようにしたいです。
つまり、各関数が同期的に順番に実行されるのではなく、非同期的に、処理が早く終わった関数から出力されるようにしたいです。
発生している問題・分からないこと
それぞれの関数を非同期にして、早く終わった関数から出力されるような非同期処理の実装方法が分からない。
該当のソースコード
javascript
1 2var func1 = async function(){ 3 console.log("func1()が実行されました。"); 4}; 5 6var func2 = async function(){ 7 for(var i = 0, j = 0; i < 100000000; i++){ 8 j = i; 9 } 10 return new Promise((resolve) => { 11 console.log("func2()が実行されました。i = " + i); 12 resolve(); 13 }); 14}; 15 16var func3 = async function(){ 17 console.log("func3()が実行されました。"); 18}; 19 20(async () => { 21 await func1(); // func1を待つ 22 await func2(); // func2を待つ 23 await func3(); // func3を待つ 24})(); 25 26
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
awaitを消したり、asyncを消したり試したが、ダメだった。
補足
特になし
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
それぞれの関数を非同期にして、早く終わった関数から出力される
という仕様ならawaitをやめればいいだけでは?
javascript
1const func1=()=>new Promise(resolve=>setTimeout(()=>(console.log(1),resolve()),100)); 2const func2=()=>new Promise(resolve=>setTimeout(()=>(console.log(2),resolve()),1000)); 3const func3=()=>new Promise(resolve=>setTimeout(()=>(console.log(3),resolve()),200)); 4func1(); 5func2(); 6func3();
※ちなみに負荷の高い処理は命題で言う大量のループ処理はそのまま回すのではなくwokerで処理をするのが懸命です
参考
workerでの処理
javascript
1<script id="myWorker" type="javascript/worker"> 2const func=(n)=>{ 3 const t=new Date().getTime(); 4 const wait=300; 5 while(new Date().getTime()<t+wait){ 6 void(0); 7 } 8 return n; 9}; 10self.addEventListener('message',e=>{ 11 self.postMessage(func(e.data)); 12}); 13</script> 14<script> 15const blob = new Blob([document.querySelector('#myWorker').textContent]); 16const worker = new Worker(window.URL.createObjectURL(blob)); 17worker.onmessage=e=>{ 18 console.log(e.data); 19} 20const func1=()=>new Promise(resolve=>setTimeout(()=>(console.log(1),resolve()),200)); 21const func2=()=>worker.postMessage(2); 22const func3=()=>new Promise(resolve=>setTimeout(()=>(console.log(3),resolve()),100)); 23func1(); 24func2(); 25func3(); 26</script>
投稿2024/10/01 02:10
編集2024/10/01 05:27総合スコア116441
0
async functionはそれだけで非同期関数です。
awaitを消せば実行を待たず(同期せず)処理されているはずです。
ほかの回答でPromise.allに触れている人がいますが、Promiseは関数の実行順序を制御するためのクラスで、質問とは関係がないので恐らく混乱します。
ちなみに、誤解されていると思いますが、setTimeoutは非同期処理をテストするためによく使われるもので、実際の重い処理をシュミレートするために使っていると思われます。
setTimeoutを使って「同期的」に処理されているのであれば質問通り不具合が出ていて、「非同期的」に処理されているのであれば質問内容は解決しています。
※質問文に記載のあるコードは明らかにおかしいですが、promiseは今回不要であるため言及しません。
追記1
あとから出しゃばっておきながら、
JavaScriptがシングルスレッドだということを完全に漏らしていました。
他回答者さんの言う通り任意の処理を別スレッドで行いたい場合、wokerを使用するのが正しい解決方法になります。
文章がごちゃつきそうなので、元の回答はあえてそのままにしますが、要望があれば修正しますり
投稿2024/10/01 04:41
編集2024/10/01 07:41総合スコア263
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2024/10/01 04:59 編集
2024/10/01 05:51
2024/10/01 06:31
2024/10/01 07:38
0
ベストアンサー
非同期メソッドに於ける非同期範囲についての誤解がある様なので そのコードでは次の問題があります。
- Promise のコンストラクタ自体は同期的に実行される
- async function は await が入るまでは同期的に実行される
- await するとその完了を待ってしまう為他の await が実行されることはない
その為、func2
は次の様にすればあとに実行されます。
(※ await Promise.resolve()
は setTimeout()
ではなく queueMicrotask()
なので 最小限の非同期となります(他の同期が優先されるだけならこれでよい
js
1var func2 = async function(){ 2 await Promise.resolve(); 3 for(var i = 0, j = 0; i < 100000000; i++){ 4 j = i; 5 } 6 console.log("func2()が実行されました。i = " + i); 7};
ただ、このままでは順番に実行されてしまうので並行実行する為に エントリーポイントを次の様に修正します
js
1(async () => { 2 await Promise.all([ 3 func1(), // func1を待つ 4 func2(), // func2を待つ 5 func3(), // func3を待つ 6 ]); 7})();
以上の修正でうまくいくと思われます。
参考:
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
https://developer.mozilla.org/ja/docs/Web/API/Window/queueMicrotask
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
追伸:
もしもそれぞれの func の先頭に await Promise.resolve()
するのであれば func2
は次の様にした方がいいかもしれません。
js
1var func2 = async function(){ 2 await Promise.resolve(); 3 for(var i = 0, j = 0; i < 100000000; i++){ 4 j = i; 5 await Promise.resolve(); 6 } 7 console.log("func2()が実行されました。i = " + i); 8};
追伸2:
javascript のメインスレッドは シングルスレッドです。この方法は await でキューに分けることで 処理を分割して並行で動作している様に見える方法なので
もしも 完全並行処理を行いたいのであればウェブワーカー API をお試しください
https://developer.mozilla.org/ja/docs/Web/API/Worker
追伸3:
ウェブワーカーAPIを使ったコードも書いておきます。
js
1var func1 = async function () { 2 console.log("func1()が実行されました。"); 3}; 4 5var func2 = async function () { 6 const source = ` 7globalThis.addEventListener('message', ({data}) => { 8 for(var i = 0, j = 0; i < data; i++){ 9 j = i; 10 } 11 globalThis.postMessage(i); 12}) 13`; 14 15 const url = `data:text/javascript;base64,${btoa(source)}`; 16 const {promise, resolve, reject} = Promise.withResolvers(); 17 const worker = new Worker(url); 18 worker.addEventListener('error', reject); 19 worker.addEventListener('messageerror', reject); 20 worker.addEventListener('message', ({data}) => resolve(data)); 21 worker.postMessage(100000000); 22 const i = await promise; 23 return new Promise((resolve) => { 24 console.log("func2()が実行されました。i = " + i); 25 resolve(); 26 }); 27}; 28 29var func3 = async function () { 30 console.log("func3()が実行されました。"); 31}; 32(async () => { 33 await Promise.all([ 34 func1(), // func1を待つ 35 func2(), // func2を待つ 36 func3(), // func3を待つ 37 ]); 38})();
投稿2024/10/01 02:20
編集2024/10/02 00:47総合スコア435
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2024/10/01 04:50
2024/10/01 05:00
2024/10/01 05:46
2024/10/01 06:03
2024/10/01 06:23
2024/10/01 06:55
2024/10/01 07:12 編集
2024/10/01 07:55
2024/10/01 08:48
2024/10/01 09:42
2024/10/01 21:12
2024/10/02 03:03
2024/10/03 22:17
2024/10/03 22:19
0
基本的には Promise.all([func1(), func2(), func3()]);
でいいものですが、質問文の例だと func2()
実行中は他の処理がブロックされるので、質問文の例そのものでは期待通りに動かすことは不可能です。
func2()
をたとえば以下のように変更すると試すことができるかと思います。
js
1const func2 = () => { 2 return new Promise(resolve => setTimeout(() => { 3 console.log("func2()が実行されました。"); 4 resolve(); 5 }, 5000)); 6};
func1()
func2()
func3()
の本来の処理内容に非同期なものが一切ない場合、それらを同時に処理を進めるには複数のスレッドが必要になります。ウェブワーカーを使うことになります。
具体的な処理内容がわかれば、また別の方法もあるかもしれません。
投稿2024/10/01 01:30
編集2024/10/01 04:53総合スコア21597
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2024/10/01 02:06
2024/10/01 02:10
2024/10/01 05:02 編集
2024/10/01 06:18
2024/10/01 06:26
2024/10/01 06:32
2024/10/01 06:35
2024/10/01 07:13
2024/10/01 07:43
2024/10/01 07:50
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。