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

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

詳細はこちら
Node.js

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

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

Q&A

解決済

1回答

1764閲覧

nodejs: Express: fetchした戻り値をexportしたいが取得した値が[Object Promise]

hokosugi

総合スコア63

Node.js

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

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

0グッド

0クリップ

投稿2021/02/22 22:38

編集2021/02/24 07:17

実現したいこと

fetchに特化したjsファイルからexportしたJsonの値をrouter.jsに送って、resでview側に渡したい。。

/* fetch.js */ const Quiz = require('./class'); const fetch = require('node-fetch'); const apiAddress = 'https://opentdb.com/api.php?amount=10'; const f = fetch(apiAddress, { method: 'get', }); const f2 = f.then(res => Promise.resolve(res.json())) .then(json => { quizArray = []; for (let i=0; i<=9; i++) { const quiz = new Quiz(); const quizCount = quiz.getQuizArray(i, json); quizArray.push(quizCount); } const quizJson = JSON.stringify(quizArray); return quizJson; }) .catch(err => console.error(err)) module.exports = f2;
/* router.js */ const express = require('express'); const router = express.Router(); const api = require('../fetch'); console.log('api:'+ api); //api:[object Promise] router.get('/', function(req, res, next) { res.render('index', { question: api[0]['quetion']//ここでjsonの配列を指定したい }); }); module.exports = router;
やってみたこと

Promiseについて理解が乏しいのですが、fetch.jsのfetchのメソッドをasync/awaitの非同期関数化してreturn quizJson取得まで待つ動作を書けばよいと思われます。しかし、どう書けばよいかまで理解が進んでいません。

【追加】
色々検索した結果、似通っている質問を見つけました。
ここ
これのExpress版が大雑把に言って私の質問になると思います。
この質問の回答にあるように現実的には難しいのではあれば、fetchしたデータをrouterを通じてどうやってview側(ejs)に渡せばよいのでしょうか?
宜しくおねがいします。

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

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

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

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

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

miyabi-sun

2021/02/24 06:49

Markdown流儀のリンクの貼り方は`[タイトル](URL)`です。 今回の例ですと [teratail-【JavaScript】fetchで取得したデータを変数にセットして自由に使いたい](https://teratail.com/questions/286024) これでぐっと見栄えが良くなると思いますので編集してみてくださいね。
hokosugi

2021/02/24 07:12 編集

ご依頼ありがとう。しかし、うまく反映しません、プレビューでは正しいリンクを付けますが・・・
miyabi-sun

2021/02/24 07:14

あー、ごくまれに上手く反映されないバグみたいなのありますね。 私が経験した時は、もう一度編集すれば動いた記憶があります。
hokosugi

2021/02/24 07:16

編集してみましたが、同じのようです。
hokosugi

2021/02/24 07:18

やっぱりうまくいきませんね。このままにしておきますw
guest

回答1

0

ベストアンサー

res.renderの実行は非同期処理の先に飛ばしても問題ありません。
fetch.jsの中身はPending中のPromiseインスタンスですので、
その中で堂々と待ちましょう。

js

1/* router.js */ 2const express = require('express'); 3const router = express.Router(); 4const api = require('../fetch'); 5 6console.log('api:'+ api); //api:[object Promise] 7router.get('/', (req, res, next) => { 8 api.then(json => { 9 res.render('index', { 10 question: json[0]['quetion'] 11 }); 12 }); 13}); 14 15module.exports = router;

async/awaitはPromiseを作ったり待つ事に特化しています。
この書き方を導入した場合、await Promiseという構文で待つ事が実現できるので
見た目だけですが同期処理のようなコードで表現出来るようになります。

js

1/* router.js */ 2const express = require('express'); 3const router = express.Router(); 4const api = require('../fetch'); 5 6console.log('api:'+ api); //api:[object Promise] 7router.get('/', async (req, res, next) => { // 関数定義する箇所でasyncキーワードを追加 8 const json = await api; // awaitキーワードを使ってPromiseの状態が完了になるまで待って値を取り出せる 9 res.render('index', { 10 question: json[0]['quetion'] 11 }); 12}); 13 14module.exports = router;

Node.jsのrequireはmodule.exportsに代入された結果をキャッシュする為、
二度目の実行では全てが省略されてmodule.exportsの結果だけを返します。
なので、基本的には関数に包んで利用者に実行タイミングを制御させた方が綺麗です。

その視点でasync/awaitまで利用するとこのようになりまう。

js

1/* fetch.js */ 2const Quiz = require('./class'); 3const fetch = require('node-fetch'); 4 5module.exports = async (apiAddress = 'https://opentdb.com/api.php?amount=10') => { 6 const res = await fetch(apiAddress, { 7 method: 'get', 8 }); 9 const json = await res.json(); 10 11 // コードが平易になったので下に普通にぶら下げれば良いね 12 const quizArray = []; 13 for (let i=0; i<=9; i++) { 14 const quiz = new Quiz(); 15 const quizCount = quiz.getQuizArray(i, json); 16 quizArray.push(quizCount); 17 } 18 19 // これis何? 20 // JSON.stringifyはJSの値を復元可能なStringに強制変換してしまうコードだよ? 21 // 以降の処理が上手く動かないならJSON.stringifyで包むのをやめてそのまま返すと上手く行くとおもう 22 return JSON.stringify(quizArray); 23};

js

1/* router.js */ 2const express = require('express'); 3const router = express.Router(); 4 5// 先に実行したければこうする 6const api = require('../fetch')(); // 値のお尻()は関数実行の証 7 8// 都度実行したければ関数のまま所持しておく 9const getApi = require(../fetch); 10 11router.get('/', async (req, res, next) => { 12 const json = await api; 13 // 都度実行したい場合はこう 14 // const json = await getApi(); 15 res.render('index', { 16 question: json[0]['quetion'] 17 }); 18}); 19 20module.exports = router;

投稿2021/02/24 07:13

編集2021/02/24 07:18
miyabi-sun

総合スコア21203

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

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

hokosugi

2021/02/24 07:21

ご回答、ありがとうございます! あ〜〜なるほど、理解できます。帰宅後早速やってみます!取り急ぎ、お礼まで。
hokosugi

2021/02/24 08:59

ありがとうございます!上手く行きました。stringifyは途中で気づいてコメントアウトしていたのですが、なんかの拍子に外してしまったのかも知れません。miyabi-sunさんは説明上手な上にお優しい方で良かったです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問