bugfix> javascript > 投稿

プロジェクトで次のコードを見つけましたが、わかりません。

get(key, store = null) {
    if (!key) {
      return new Error('There is no key to get!');
    }
    let dbstore = this.localforage;
    if (store !== null) {
      dbstore = store;
    }
    return dbstore
      .getItem(key)
      .then(function(value) {
        return value;
      })
      .catch(function(err) {
        return new Error('The key (' + key + ") isn't accessible: " + err);
      });
  }

なぜ return new Error('There is no key to get!');   throw new Error('There is no key to get!'); の代わりに

また、なぜ catch でエラーをスローしないのか  ブロックしますか?

回答 1 件
  • 関数インターフェースを設計し、対処するエラーがある場合、エラーを返す方法について設計上の選択肢があります。関数が同期の場合、エラーを示し、実際の結果と簡単に区別されるセンチネル値を返すことができます(多くの場合、 null  Javascriptで)または throw できます  例外、または操作の成功または失敗を示すプロパティを持つオブジェクトを返すことができます。

    promiseインターフェースを使用した非同期操作がある場合、通常は Promise を拒否します   Error と  エラーを示す拒否理由としてのオブジェクト。それが約束の核となる設計理論です。成功はオプションの値で解決され、エラーは理由で拒否されます。

    このコードブロック:

    return dbstore
      .getItem(key)
      .then(function(value) {
        return value;
      })
      .catch(function(err) {
        return new Error('The key (' + key + ") isn't accessible: " + err);
      });
    
    

    返されたプロミスを値または Error で解決しています  オブジェクト。これは一般的にプロミスコードの記述方法ではありません。プロミスを使用する単純で簡単な方法ではないエラーがあるかどうかを判断するために、呼び出し側が解決された値の型をテストする必要があるためですだから、あなたの質問に、あなたは通常これをするでしょう:

    return dbstore.getItem(key).catch(function(err) {
        throw new Error('The key (' + key + ") isn't accessible: " + err);
    });
    
    

    この関数には他の兆候がありますが、それは単なる悪いコードです。

    .then(function(value) {return value;})  完全に不要で不要です。それはまったく価値を追加しません。ザ・ value  すでに約束の解決された価値です。再度宣言する必要はありません。

    この関数は、promiseを返すことがあり、同期例外をスローすることもあります。
    これはさらに使いにくいです。最初の if (!key) { を見ると  ステートメント、Errorオブジェクトを返します key  引数が指定されていません。つまり、この関数を使用するには、同期例外をキャッチし、 .then() を提供する必要があります。  および .catch()  ハンドラーAND解決されたプロミスのタイプをチェックして、エラーオブジェクトであるかどうかを確認します。この機能は悪夢です。悪いコードです。

    関数をそのまま使用するには、呼び出し側がこれを行う必要があります:

    let retVal = someObj.get(aKey);
    if (typeof retVal === Error) {
        // got some synchronous error
    } else {
        retVal.then(val => {
            if (typeof val === Error) {
                // got some asynchronous error
            } else {
                // got an actual successful value here
            }
        }).catch(err => {
            // got some asynchronous error
        })
    }
    
    

    関数の実装はおそらく次のようになります:

    get(key, store = null) {
        if (!key) {
            return Promise.reject(new Error('There is no key to get!'));
        }
        let dbstore = store || this.localforage;
        return dbstore.getItem(key).catch(function(err) {
            throw new Error('The key (' + key + ") isn't accessible: " + err);
        });
    }
    
    

    これは次のように使用できます:

    someObj.get(aKey).then(val => {
        // got some successful value here
    }).catch(err => {
        // got some error here
    });
    
    

    ここでの呼び出し元の単純さと上記の混乱を比較してください。

    この実装には次の一貫性があります:

    常に約束を返します。 key の場合  提供されず、拒否されたプロミスを返します。

    すべてのエラーは、拒否されたプロミスを介して発生します

    Promiseが解決する値は常に実際の成功値です

    .then() はありません  役に立たないハンドラ。

あなたの答え