web-dev-qa-db-ja.com

約束を解決または拒否しないとどうなりますか

約束を返すシナリオがあります。基本的に、約束はajaxリクエストのレスポンスを提供します。

約束を拒否すると、サーバーエラーがあることを示すエラーダイアログが表示されます。

私がやりたいのは、応答コードが401のとき、約束を解決したり拒否したりしないことです(エラーダイアログが表示されるため)。ログインページにリダイレクトしたいだけです。

私のコードは次のようになります

function makeRequest(ur,params) {

    return new Promise(function(resolve,reject) {

        fetch(url,params)
        .then((response) => {

            let status = response.status;

            if (status >= 200 && status < 300) {
                response.json().then((data) => {
                    resolve(data);
                })
            }
            else {
                if(status === 401) {
                    redirectToLoginPage();
                }
                else {
                    response.json().then((error) => {

                        if (!error.message) {
                            error.message = constants.SERVER_ERROR;
                        }
                        reject({status,error});
                    })    
                }
            }

        })
    });
}

ステータスが401かどうかを確認できるように、ログインページにリダイレクトしています。約束は解決も拒否もされません。

このコードは大丈夫ですか?または、これを達成するためのより良い方法はありますか。

ありがとう。

51
Aniket

Promiseは、Javascriptのプロパティを持つオブジェクトです。魔法はありません。したがって、約束の解決または拒否に失敗すると、状態を「保留」から他の状態に変更できなくなります。 promiseは単なる通常のJavaScriptオブジェクトであるため、これはJavascriptに根本的な問題を引き起こすことはありません。 Promiseへの参照を保持するコードがない場合でも、Promiseはガベージコレクションされます(まだ保留中であっても)。

ここでの本当の結果は、その状態が変更されない場合、約束の消費者にとって何を意味するのでしょうか?トランジションを解決または拒否するための.then()または.catch()リスナーは呼び出されません。 promiseを使用するほとんどのコードは、将来のある時点で解決または拒否することを期待しています(そのため、promiseが最初に使用される理由です)。そうでない場合、そのコードは通常、作業を完了できません。

そのタスクの作業を終了する他のコードが存在する可能性があり、そのことは実行されずに約束が破棄されるだけです。 Javascriptにそのような方法で内部問題はありませんが、Promiseが機能するように設計された方法ではなく、Promiseの消費者がそれらが機能することを期待する方法ではありません。

ステータスが401かどうかを確認できるように、ログインページにリダイレクトしています。約束は解決も拒否もされません。

このコードは大丈夫ですか?または、これを達成するより良い方法があります。

この特定のケースでは、それはすべて大丈夫であり、リダイレクトはやや特別でユニークなケースです。新しいブラウザページへのリダイレクトは、現在のページの状態(すべてのJavascriptの状態を含む)を完全にクリアするため、リダイレクトでショートカットを使用し、他のものを未解決のままにしておくことはまったく問題ありません。新しいページの読み込みが開始されると、システムはJavascriptの状態を完全に再初期化するため、まだ保留中だったプロミスはクリーンアップされます。

73
jfriend00

約束を常に解決または拒否します。結果を今すぐ使用していない場合でも、この作業にもかかわらず、エラーを飲み込むための約束があり、コードが複雑になるほど難しくなるので、入るのは非常に悪い習慣です明示的に約束を完了しなかったいくつかの場所を見つけることです(さらに、それが問題なのかどうかさえわかりません)。

7
kungphu

「リジェクトを解決しないとどうなるか」という答えは正しかったと思います。.thenを追加するか.catchを追加するかはあなたの選択です。

ただし、このコードは大丈夫ですか?または、これを達成するためのより良い方法はありますか。私は2つのことがあると思います:

Promiseをnew Promiseでラップする必要があり、fetch呼び出し失敗する可能性があるの場合、呼び出しメソッドが座っていないように行動する必要があります。解決されない約束を待ちます。

次に例を示します(100%確実ではなく、ビジネスロジックで機能するはずです)。

const constants = {
  SERVER_ERROR: "500 Server Error"
};
function makeRequest(url,params) {
  // fetch already returns a Promise itself
  return fetch(url,params)
        .then((response) => {

            let status = response.status;

            // If status is forbidden, redirect to Login & return nothing,
            // indicating the end of the Promise chain
            if(status === 401) {
              redirectToLoginPage();
              return;
            }
            // If status is success, return a JSON Promise
            if(status >= 200 && status < 300) {
              return response.json();
            }
            // If status is a failure, get the JSON Promise,
            // map the message & status, then Reject the promise
            return response.json()
              .then(json => {
                if (!json.message) {
                    json.message = constants.SERVER_ERROR;
                }
                return Promise.reject({status, error: json.message});
              })
        });
}
// This can now be used as:
makeRequest("http://example", {})
  .then(json => {
    if(typeof json === "undefined") {
      // Redirect request occurred
    }
    console.log("Success:", json);
  })
  .catch(error => {
    console.log("Error:", error.status, error.message);
  })

対照的に、次を使用してコードを呼び出す:

makeRequest("http://example", {})
  .then(info => console.log("info", info))
  .catch(err => console.log("error", err));

http://exampleの呼び出しは失敗するため、何もログに記録されませんが、catchハンドラーは実行されません。

4
CodingIntrigue

makeRequestの呼び出し元が約束を果たすことを期待する場合を除いて、それは機能し、実際には問題ではありません。だから、あなたはそこで契約を破っている。

代わりに、約束を延期するか、(この場合)ステータスコード/エラーで拒否することができます。

2
nullpotent

他の人が述べたように、あなたが約束を解決/拒否しなければ、それは本当に問題ではないことは事実です。とにかく、私はあなたの問題を少し解決します:

function makeRequest(ur,params) {

    return new Promise(function(resolve,reject) {

        fetch(url,params)
        .then((response) => {

            let status = response.status;

            if (status >= 200 && status < 300) {
                response.json().then((data) => {
                    resolve(data);
                })
            }
            else {
                reject(response);
            }
        })
    });
}

makeRequest().then(function success(data) {
   //...
}, function error(response) {
    if (response.status === 401) {
        redirectToLoginPage();
    }
    else {
        response.json().then((error) => {
            if (!error.message) {
                error.message = constants.SERVER_ERROR;
            }

            //do sth. with error
        });
    } 
});

つまり、すべての悪い応答状態を拒否し、makeRequesterror handlerでこれを処理します。

2
Fidel90