3

このデータが にあるとしますspanish.json:

[
   {"word": "casa", "translation": "house"},
   {"word": "coche", "translation": "car"},
   {"word": "calle", "translation": "street"}
]

そして、それをロードして検索メソッドを追加する Dictionary クラスがあります。

// Dictionary.js
class Dictionary {
  constructor(url){
    this.url = url;
    this.entries = []; // we’ll fill this with a dictionary
    this.initialize();
  }

  initialize(){
    fetch(this.url)
      .then(response => response.json())
      .then(entries => this.entries = entries)
  }

  find(query){
    return this.entries.filter(entry => 
      entry.word == query)[0].translation
  }
}

そして、それをインスタンス化し、それを使用して、この小さな単一ページのアプリで「calle」を検索できます。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>spanish dictionary</title>
</head>
<body>

<p><input placeholder="Search for a Spanish word" type="">  
<p><output></output>

<script src=Dictionary.js></script>
<script>

  let es2en = new Dictionary('spanish.json')
  console.log(es2en.find('calle')) // 'street'

  input.addEventListener('submit', ev => {
    ev.preventDefault();
    let translation = dictionary.find(ev.target.value);
    output.innerHTML = translation;
  })

</script>


</body>
</html>

ここまでは順調ですね。Dictionary しかし、サブクラス化して、すべての単語をカウントし、そのカウントをページに追加するメソッドを追加したいとしましょう。(男、投資家が必要です。)

それで、私は別のラウンドの資金を得て、次のことを実装しCountingDictionaryます。

class CountingDictionary extends Dictionary {
  constructor(url){
    super(url)
  }

  countEntries(){
    return this.entries.length
  }
}

新しい単一ページ アプリ:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Counting Spanish Dictionary</title>
</head>
<body>

<p><input placeholder="Search for a Spanish word" type="">  
<p><output></output>

<script src=Dictionary.js></script>
<script>


  let 
    es2en = new CountingDictionary('spanish.json'),
    h1 = document.querySelector('h1'),
    input = document.querySelector('input'),
    output = document.querySelector('output');

  h1.innerHTML = es2en.countEntries();

  input.addEventListener('input', ev => {
    ev.preventDefault();
    let translation = es2en.find(ev.target.value);
    if(translation)
      output.innerHTML = `${translation}`;
  })

</script>

</body>
</html>

このページが読み込まれると、h1が読み込まれ0ます。

私は自分の問題が何であるかを知っていますが、それを修正する方法がわかりません。

問題は、fetch呼び出しが を返し、PromisePromise.entriesが返されたときにのみプロパティに URL からのデータが入力されることです。それまでは、 .entries空のままです。

.countEntriesfetch promise が解決するのを待つにはどうすればよいですか?

または、ここで私が望むものを完全に達成するためのより良い方法はありますか?

4

3 に答える 3

5

問題は、fetch呼び出しが を返し、PromisePromise.entriesが返されたときにのみプロパティに URL からのデータが入力されることです。それまでは、 .entries空のままです。

entries約束をする必要があります。そうすれば、すべてのメソッドが promise を返さなければなりませんが、Dictionaryインスタンスはすぐに使用できます。

class Dictionary {
  constructor(url) {
    this.entriesPromise = fetch(url)
      .then(response => response.json())
  }
  find(query) {
    return this.entriesPromise.then(entries => {
       var entry = entries.find(e => e.word == query);
       return entry && entry.translation;
    });
  }
}
class CountingDictionary extends Dictionary {
  countEntries() {
    return this.entriesPromise.then(entries => entries.length);
  }
}

let es2en = new CountingDictionary('spanish.json'),
    h1 = document.querySelector('h1'),
    input = document.querySelector('input'),
    output = document.querySelector('output');

es2en.countEntries().then(len => {
  fh1.innerHTML = len;
});
input.addEventListener(ev => {
  ev.preventDefault();
  es2en.find(ev.target.value).then(translation => {
    if (translation)
      output.innerHTML = translation;
  });
});

または、ここで私が望むものを完全に達成するためのより良い方法はありますか?

はい。Is it bad practice to have a constructor function return a Promise? をご覧ください。.

class Dictionary {
  constructor(entries) {
    this.entries = entries;
  }  
  static load(url) {
    return fetch(url)
      .then(response => response.json())
      .then(entries => new this(entries));
  }

  find(query) {
    var entry = this.entries.find(e => e.word == query);
    return entry && entry.translation;
  }
}
class CountingDictionary extends Dictionary {
  countEntries() {
    return this.entries.length;
  }
}

let es2enPromise = CountingDictionary.load('spanish.json'),
    h1 = document.querySelector('h1'),
    input = document.querySelector('input'),
    output = document.querySelector('output');

es2enPromise.then(es2en => {
  fh1.innerHTML = es2en.countEntries();
  input.addEventListener(…);
});

ご覧のとおり、このアプローチでは、promise を含むインスタンスと比較して、全体的なネストが少なくて済みます。また、インスタンスの promise の方が構成しやすいです。たとえば、リスナーをインストールして出力を表示する前に domready を待つ必要がある場合、DOM の promise を取得し、両方を使用して待つことができPromise.allます。

于 2016-09-08T15:36:08.353 に答える
0

呼び出しの結果を変数に割り当てる必要がありfetch()ます。たとえば、次のようになります。

initialize(){
  this.promise = fetch(this.url)
    .then(response => response.json())
    .then(entries => this.entries = entries)
}

then()次に、そのメソッドを呼び出すことができます。

let es2en = new CountingDictionary('spanish.json'),
    h1 = document.querySelector('h1'),
    input = document.querySelector('input'),
    output = document.querySelector('output');

es2en.promise.then(() => h1.innerHTML = es2en.countEntries())

input.addEventListener('input', ev => {
  ev.preventDefault();
  let translation = es2en.find(ev.target.value);
  if(translation)
    output.innerHTML = `${translation}`;
})
于 2016-09-08T15:36:00.393 に答える
0

簡単な解決策: 実行後に約束を守り、クラスが完全に初期化されるまで待機できるメソッドをfetch()追加します。ready()

class Dictionary {
  constructor(url){
    /* ... */

    // store the promise from initialize() [see below]
    // in an internal variable
    this.promiseReady = this.initialize();
  }

  ready() {
    return this.promiseReady;
  }

  initialize() {
    // let initialize return the promise from fetch
    // so we know when it's completed
    return fetch(this.url)
      .then(response => response.json())
      .then(entries => this.entries = entries)
  }

  find(query) { /* ... */ }
}

次に、オブジェクトを構築した後に呼び出すだけ.ready()で、いつロードされるかがわかります。

let es2en = new CountingDictionary('spanish.json')
es2en.ready()
  .then(() => {
    // we're loaded and ready
    h1.innerHTML = es2en.countEntries();
  })
  .catch((error) => {
    // whoops, something went wrong
  });

少し余分な利点として、.catchロード中に発生するエラー (ネットワーク エラーやキャッチされていない例外など) を検出するために使用できます。

于 2016-09-08T15:38:32.317 に答える