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

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

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

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

JavaScript

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

Q&A

解決済

1回答

4184閲覧

Node.js : 非同期処理の途中で、変数が適切に受け渡せない

dwayne_johnson

総合スコア86

Node.js

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

JavaScript

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

0グッド

0クリップ

投稿2018/08/21 08:06

Promise を使用した非同期処理の途中でエラーが出てしまいます。

getMdFileFromStorage(md_data_path) .then((md_data) => { console.log("next action is mdToHtml"); return mdToHtml(md_data) }) .then((body_html) => { data.body = body_html; console.log("data is now have html : ", data); return buildHtml(data); }) .then((html) => { console.log("compiled html is send to next func : ", html); // ここの html が undefined に

上記に記載の最後の行で、変数が正しく受け渡せていない状況です。

その一つ前で実行されている関数buildHtml()は、以下

const buildHtml = (data) => { ejs.renderFile('src/main_amp.ejs', { filename: 'src/main_amp.ejs', data: data }, 'utf-8', (error, html) => { if (error) { throw error; } console.log("html by ejs is this : ", html); // ここの html は 成功してる return html; } ) }

eje.renderFileの結果をreturnしたいのですが、適切に返せていない状況で、いろいろ試行錯誤したのですがどれもうまくいきません。

具体的には、
・ ejs.renderFileの前にもreturnを付け、それ自体を返すようにする
・ const html = eje.renderFileとし、その後return html;してみる

どこに問題があるか、ご指南いただきたいです。
よろしくお願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

こういう時のPromiseでしょ!!
thenの戻り値は値かPromise期待で、Promiseの場合はresolveまで待ってくれます。
なので下記のようにbuildHtml関数を変更すれば動作するでしょう。

JavaScript

1const buildHtml = data => new Promise((resolve, reject) => { 2 ejs.renderFile('src/main_amp.ejs', { 3 filename: 'src/main_amp.ejs', 4 data: data 5 }, 'utf-8', 6 (error, html) => { 7 if (error) return reject(error); 8 console.log("html by ejs is this : ", html); // ここの html は 成功してる 9 resolve(html); 10 } 11 ) 12});

解説

JavaScriptやNode.jsはシングルスレッドです。
なのでインターネットの通信やハードディスクのくっそ遅い読み書きをちんたら待ってられません。
その間発生した他のイベントとか発生しても全部止まってしまう。

じゃあどうするか?
関数を書き置きとして利用します。
関数は見方を変えれば、尻に()を付けたら実行し始める「TODOリスト」と読み替える事も可能ですよね。

JSでは変数に関数を代入、関数の引数として設定、関数の戻り値として設定
…などといった普通の値と同じ待遇になっています。
(この特性を第一級オブジェクト等と読んだりします。)

これを利用してやりたい事を関数として包んでおいて、
非同期の関数の引数として注入してあげます。
これが非同期処理の一般的なコールバック関数による解決方法。

イメージとしては、子供を学校に送り出したお母さんは、
家の掃除やら料理やらで忙しいので、sleepで子供の帰宅をひたすら待っている訳にはいきません。
そこで予め「帰って来たら手を洗って、プリントを机の上に出す」という書き置きを作って置きます。
すると子供が帰ってきたら書き置きを読んでそのとおりに実行します。

こういう考え方をします。


ライブラリ等がこの手法を用いるという事は、
ハードディスクやHTTPリクエスト等の遅い処理だから、
非同期にして切り離そうという意思表示に他なりません。

最終引数のコールバック関数を書き置きとして保存し続けておいて、
HTTPリクエスト等の完了を待ってから関数を実行します。
(詳細が知りたければイベントループ等で調べてみてください)

当然JSはそんな事待ってられないので、その行はスルーして下へ流れて行きます。
従ってコールバック関数内で実行したthrowreturnは外側では受け取る事が出来ません。
try〜catch構文で包んで居ても、受付が正常終了した時点で終わってしまいますね。

…まぁ、この関数≒書き置きという考え方の基本はPromiseでも完全に同様なので覚えて置きましょう。
.then(fn)メソッドで渡す関数の中身は、引数等の書式が違うだけの書き置きですからね。

投稿2018/08/21 08:23

編集2018/08/21 08:26
miyabi-sun

総合スコア21158

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

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

dwayne_johnson

2018/08/22 10:04

こういう時のPromiseでした。 詳しくご説明、助かりました。 これ以外の箇所でも、Promise他非同期処理周りでいろいろ詰まる箇所が多いので、もっとしっかりPromise関連について学ぼうと思います。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問