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

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

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

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

Q&A

解決済

2回答

1659閲覧

非同期処理で取得したデータをクラスのプロパティに入れたいです

takopo

総合スコア484

JavaScript

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

0グッド

0クリップ

投稿2020/09/22 04:39

編集2020/09/22 07:06

質問させてください。
下のようなコードを作成しまして、C クラスには外部から json データを取得するメソッドがあり、new A()を実行したときに、そこで取得したデータを C クラスのプロパティに格納したいと思っております。
しかし下のコードだとfecth()が原因のためか中身が空の状態になってしまいます。

javascript

1class A { 2 constructor() { 3 this.b = new B(); 4 } 5} 6 7class B { 8 constructor() { 9 this.c = new C(); 10 } 11} 12 13class C { 14 constructor() { 15 this.data = this.fetchData(); // ← ここのプロパティに取得したデータを入れたいです 16 console.log(this.data); // undefined 17 } 18 19 // json からデータを取得 20 fetchData() { 21 fetch('sample.json') 22 .then(res => { 23 return res.json(); 24 }) 25 } 26} 27 28const a = new A();

そこで下のように非同期処理が終わるのを待つためにawaitを使おうと思ったのですが、コンストラクターにはasyncが使えないらしく、エラーになってしまいます。

javascript

1async constructor() { 2 this.data = await this.fetchData(); 3}

こちらのページを参考に init() を作ってみてもうまくいきませんでした・・・

javascript

1class C { 2 constructor() { 3 this.init(); 4 } 5 6 async init() { 7 this.data = await this.fetchData(); 8 console.log(this.data); 9 } 10 11 fetchData() { 12 fetch('sample.json') 13 .then(res => { 14 return res.json(); 15 }) 16 } 17}

もし解決方法をご存じの方がいらっしゃいましたらご教授いただけると助かります。
よろしくお願いいたします。

追記

gentaro様からのアドバイスをもとに修正しました。

javascript

1class A { 2 constructor(data) { 3 this.b = new B(data); 4 } 5 6 start() { 7 this.b.active(); 8 } 9} 10 11class B { 12 constructor(data) { 13 this.c = new C(data); 14 } 15 16 active() { 17 this.c.hoge(); 18 } 19} 20 21class C { 22 constructor(data) { 23 this.data = data; 24 console.log(this.data); 25 } 26 27 hoge() { 28 // このメソッドで取得したデータを使います 29 } 30} 31 32// json からデータを取得 33fetch('sample.json') 34 .then(res => { 35 return res.json(); 36 }) 37 .then(data => { 38 // Aクラスのインスタンスを生成 39 const a = new A(data); 40 41 // ゲームをスタート 42 a.start(); 43 });

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

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

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

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

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

gentaro

2020/09/22 05:19

シンプルに非同期で取得したデータをコンストラクタで渡すだけじゃダメなの? コンストラクタそのものを非同期にするとか、無駄にややこしくしてる気がしますが。
takopo

2020/09/22 06:28

ありがとうございます。 すみません、データをコンストラクタで渡すというのはAクラスの中で fetchData() を実行するということでしょうか…理解不足ですみません
gentaro

2020/09/22 06:36

いや、コンストラクタは普通に引数で値をもらうだけ、という意味で。 そのクラスを利用する側がfetchして、取得したデータをコンストラクタの引数に渡せばいいだけで、いま定義したいクラスの内部に非同期とかのややこしいコードを入れる必要あるの?という疑問です。
takopo

2020/09/22 10:03 編集

ご返答ありがとうございます。 実はややこしくなると思い書いてなかったのですが、Aクラスの中に start() というメソッドがありまして、そのメソッドを実行したらゲームがスタートするというものを作っています。 いただいたアドバイスをもとに修正したコードを追記しました。こちらで取得したデータをCクラスのプロパティに入れることはできたのですが、Cクラスのメソッド内でしか使わないプロパティを外から取得しないといけないのでしょうか。Cクラス内で取得から保持まで完結できれば、まとまっていて良さそうなのですがどうでしょうか…
guest

回答2

0

こんなのはどうでしょうか?
コンストラクタはどうしても非同期にできないので、ファクトリーを作るか、作った後から初期化する必要がありますね。

HTML

1<!DOCTYPE html> 2<html lang="ja"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>Document</title> 7</head> 8<body> 9 <script> 10 class C { 11 async init() { 12 this.data = await fetch("john.json").then(a => a.json()); 13 return this; 14 } 15 } 16 17 (async () => { 18 const c = await new C().init(); 19 console.log(c.data.name); 20 })(); 21 </script> 22</body> 23</html>

JSON

1{ "name": "John" }

投稿2020/09/24 12:49

編集2020/09/24 13:53
Zuishin

総合スコア28660

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

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

takopo

2020/09/25 01:37

ご回答ありがとうございます。 インスタンス作成後に初期化するにはこのようにしたらよかったのですね。無事にプロパティに入れることができました。 今回お二方に素晴らしいご回答をいただけてとても感謝しております。ベストアンサーは迷ったのですが、最初にご回答いただいたAkitoshiManabe様にさせていただきたいと思います。Zuishin様申し訳ございません。 今回は本当にありがとうございました!
guest

0

ベストアンサー

fetch をclassブロックのメソッドの中で使う場合、アロー関数(this は宣言したスコープになる)を使い、適切にコールバック内でプロパティに値を格納するだけです。

json

1{"sample":"SAMPLE"}

javascript

1/* omitted class A{}, class B{} */ 2 3class C { 4 constructor() { 5 this.fetchData(); 6 console.log(this.data); // undefined 7 } 8 9 // json からデータを取得 10 fetchData() { 11 fetch('sample.json') 12 .then( res => res.json() ) 13 .then( json => { 14 this.data = json 15 }) 16 } 17} 18 19const a = new A(); 20console.log( a.b.c ); 21/* 22// fetch によるsample.json 読み込み完了後: 23C {} 24 data: 25 sample: "SAMPLE" <---- data プロパティに入っています。 26 __proto__: Object 27 __proto__: Object 28 */ 29console.log( a.b.c.data ) 30// => {sample: "SAMPLE"}

追記)

fetch の遅延を考える

javascript

1/* omitted */ 2 fetchData() { 3 fetch('sample.json') 4 .then(res => res.json()) 5 .then( json => { 6 this.data = json; 7 if( "function" === typeof this.onload ) { 8 this.onload(this); 9 } 10 }) 11 } 12/* omitted */ 13const a = new A(); 14a.b.c.onload = function(c){ 15 alert(JSON.stringify(c.data)); 16}

投稿2020/09/24 09:59

編集2020/09/24 12:09
AkitoshiManabe

総合スコア5432

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

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

takopo

2020/09/24 11:35

ご回答ありがとうございます。 すみません、教えていただいたコードを試してみたのですが、最後の console.log( a.b.c.data ) というところが undefined になってしまいます…どこか見落としているところがあるのでしょうか。。
AkitoshiManabe

2020/09/24 11:59

> どこか見落としているところ 非同期ですので、class C の メソッドで this.data = json の処理には遅延があります。 コメント「fetch によるsample.json 読み込み完了後:」は a.b.c.data も同様ですね。
takopo

2020/09/25 01:36

遅くなってすみません。たびたびのご返信ありがとうございます。 this.data = json の処理は const a = new A(); よりも後になってしまうのが原因だったのですね。 非同期完了を待つ処理まで書いていただいてありがとうございます。 こちらで無事に解決でき助かりました。大変勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問