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

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

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

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

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

2回答

726閲覧

Node.jsの非同期処理関数の戻り値

nosuke09

総合スコア9

Node.js

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

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2023/01/04 12:09

前提

Reactとバックエンドをnode.jsでTodoアプリを作成しています。
バックエンドとの通信はaxiosを使用しています。

実現したいこと

一言だと非同期処理関数の戻り値のPromiseではなく、取りたい値をスマートに返すことはできない、もしくは取得できないかという質問です。
そもそもこのような書き方をするのか分からないのですが、APIとの通信をするためのファイルとしてjsファイルを作成し
この中でメソッドを定義しました。
通信自体はうまくいき全てのタスクを読み込み、名前を取り出せています。

const showTasks = async () => { try { const { data: tasks } = await axios.get(); // console.log(tasks); // タスクを出力 const allTasks = tasks.map((task) => { const { name } = task; return name; }); return allTasks; } catch(err) { console.log(err); } };

ここで上記のallTasksという変数にタスクがある分だけnameを取ってきています。これをjsxのファイルで受け取って
表示させたいと思い、showTasksをexportし、jsxのファイルにimport。
ここで中身を下のように確認してみたところ

const List = () => { const allTasks = showTasks(); console.log(allTasks); }

console.logの結果

Promise {<pending>} [[Prototype]] Promise [[PromiseState]] "fulfilled" [[PromiseResult]] Array(2)

非同期処理を行った関数の戻り値はPromiseになるとのことで取得したい結果が取れません。
色々試行錯誤してみて

const allTasks = showTasks().then((result) => console.log(result));

こうすると取得したいnameを表示できるのですが変数に収めることはできません。
スマートに非同期処理関数の戻り値を取得する方法はないでしょうか?

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

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

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

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

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

guest

回答2

0

ベストアンサー

async/await構文を覚えましょう

js

1const showTasks = async () => { 2 try { 3 const { data: tasks } = await axios.get(); 4 // 分割代入するだけなのでこれでよくね? 5 return tasks.map(({name}) => name); 6 } catch(err) { 7 console.log(err); 8 // 関数がエラーを握りつぶすのは良くないので改めてthrowする 9 throw err; 10 } 11}; 12 13const List = async () => { 14 const allTasks = await showTasks(); 15 console.log(allTasks); 16}

非同期処理を行った関数の戻り値はPromiseになるとのことで取得したい結果が取れません。

不可能です。

JavaScriptはシングルスレッドなので、
HTTP通信等の時間がかかる遅いタスクが間に挟まると
ブラウザ全体を巻き込んで応答不能になり操作を受け付けなくなります。

そこで、JavaScriptはイベントという仕組みを使って待つ事を実現させました。
「HTTP通信等の時間がかかる遅いタスク」が終わった後に実行したい内容を、
予め関数化してまとめておき、イベントリスナーに登録します。

イベントリスナーは登録時「了解、巡回して処理が完了している事を完了したら関数実行しておくわ」と受理します。
そして関数の中身は受け取るだけでスルー
全ての処理が終わって暇になったら「そういやあの処理終わってるかな?」と巡回しては関数を1個取り出して実行。
これがイベントループです。

なので、非同期処理がイベントを採用している限り同期処理の世界に戻ってくる事は出来ません。
イベントリスナーに関数を預けて、察知できないタイミングで関数を実行してもらうだけの話ですからね。

これはPromiseを使おうが、async/awaitを使おうが
JavaScriptがイベントという仕組みを採用している限り絶対に覆す事は出来ません。

スマートに非同期処理関数の戻り値を取得する方法はないでしょうか?

同期処理には二度と戻れない、
これはJavaScriptでプログラミングしている人の全員が感じる不満となります。

非同期処理はイベント登録なので、ストンとスルーするしかないので、
結果を受け取って判断したくてもif文もfor文も受け付けず、ただ関数を作りまくるしかない。
何のためのC言語風の構文なんだよ全然役にたたねえ。

なので、この関数を作って管理しなければならないという成約を突破するために
Promise→async/awaitが開発されました。

これにより、実際には非同期処理を挟んだら同期処理には帰って来られないが、
JavaScriptを書いている間はasync/await構文を活用することで
まるで非同期処理を同期処理の中であるかのように扱う事が可能となりました。

js

1// await構文を有効にするためにasync関数を定義する 2const List = async () => { 3 // showTasksはasync関数なので、必ずPromiseのインスタンスになる 4 // つまりawait構文を使ってthenメソッドで値を取り出す事が可能となる 5 const allTasks = await showTasks(); 6 console.log(allTasks); 7}

これならば十分スマートと言っても良いと思います。

投稿2023/01/05 06:49

miyabi-sun

総合スコア21163

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

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

0

スマートに非同期処理関数の戻り値を取得する方法はないでしょうか?

Reactなのでしたら、直接取ろうとはしないほうがやりやすいです。

  • Promiseがresolveした時点で、stateに中身を流し込む
  • stateから必要な描画を行う

この2つのコードを書いておけば、非同期であることをあまり気にせず描画を行うことができます。

投稿2023/01/04 13:30

maisumakun

総合スコア145332

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

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

nosuke09

2023/01/05 04:20

Stateを利用する場合は、API通信を行なって値を取ってくるための関数は別ファイルとして切り分けない方が良いということでしょうか? 私の認識だとStateは同一コンポーネントないし親子関係がないと参照できなかったと思うのですが。 今回の場合であればListコンポーネントの中で非同期処理を記述してStateに値を渡すといった具合でしょうか? ``` const List = () => { const [name, setName] = useState(""); const showTasks = async () => { try { // APIを叩く const { data: tasks } = await axios.get(); // console.log(tasks); // タスクを出力 const allTasks = tasks.map((task) => { const { completed, _id, name } = task; // ListのHTML要素をTaskの数だけ返す return name; }); return allTasks; } catch(err) { console.log(err); } }; setName(showTasks()); } ```
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.44%

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

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

質問する

関連した質問