web-dev-qa-db-ja.com

未処理のプロミス拒否とは何ですか?

Angular 2を学習するために、私は彼らのチュートリアルを試しています。

次のようなエラーが表示されます。

(node:4796) UnhandledPromiseRejectionWarning: Unhandled promise rejection (r                                                                                                     ejection id: 1): Error: spawn cmd ENOENT
[1] (node:4796) DeprecationWarning: Unhandled promise rejections are deprecated.
In the future, promise rejections that are not handled will terminate the Node.
js process with a non-zero exit code.

SOでさまざまな質問と回答を行いましたが、「未処理の約束拒否」が何であるかを見つけることができませんでした。

誰が私にそれが何であるか、そしてError: spawn cmd ENOENTが何であるか、それがいつ発生し、この警告を取り除くために何をチェックする必要があるかを簡単に説明できますか?

このエラーの原因は、ありとあらゆる約束が約束拒否を処理することが期待される、すなわち、 .catch(...) を持つことにある。以下のように、コード内の約束に .catch(...) を追加することで、これを回避できます。

たとえば、関数PTest()は、グローバル変数 somevar の値に基づいて、約束を解決または拒否します。

var somevar = false;
var PTest = function () {
    return new Promise(function (resolve, reject) {
        if (somevar === true)
            resolve();
        else
            reject();
    });
}
var myfunc = PTest();
myfunc.then(function () {
     console.log("Promise Resolved");
}).catch(function () {
     console.log("Promise Rejected");
});

場合によっては、 "未処理の約束拒否" というメッセージが、約束のために.catch(..)が書かれていても表示されます。コードの書き方がすべてです。次のコードは、たとえcatchを処理していても、 "未処理の約束拒否" を生成します。

var somevar = false;
var PTest = function () {
    return new Promise(function (resolve, reject) {
    if (somevar === true)
        resolve();
    else
        reject();
});
}
var myfunc = PTest();
myfunc.then(function () {
     console.log("Promise Resolved");
});
// See the Difference here
myfunc.catch(function () {
     console.log("Promise Rejected");
});

違いは、.catch(...)をチェーンとしてではなく、別々に扱うということです。どういうわけかJavaScriptエンジンは未処理の約束拒否をせずにそれを約束として扱います。

145
Daksh

これはPromise.reject()で完了した場合、またはasync実行コードで例外がスローされ、.catch()が拒否を処理しなかった場合です。

拒否された約束は、アプリケーションのエントリポイントに向かってバブルアップし、ルートエラーハンドラにその出力を生成させる例外のようなものです。

また見なさい

29

約束は拒否された後に「処理」されます。つまり、catchハンドラを提供する前に、promiseの拒否コールバックを呼び出すことができます。この振る舞いは私には少し面倒です。

var promise = new Promise(function(resolve) {
kjjdjf(); // this function does not exist });

...そしてこの場合、約束は黙って拒絶されます。キャッチハンドラの追加を忘れた場合、コードはエラーなしで静かに実行され続けます。これは長引かず見つけにくいバグにつながる可能性があります。

Node.jsの場合、未処理のPromise拒否を処理して問題を報告するという話があります。これでES7に非同期になります。この例を考えてください。

async function getReadyForBed() {
  let teethPromise = brushTeeth();
  let tempPromise = getRoomTemperature();

  // Change clothes based on room temperature
  let temp = await tempPromise;
  // Assume `changeClothes` also returns a Promise
  if(temp > 20) {
    await changeClothes("warm");
  } else {
    await changeClothes("cold");
  }

  await teethPromise;
}

上の例では、getRoomTemperatureが満たされる前にteethPromiseが拒否されたとします(エラー:歯磨き粉のうち!)。この場合、歯を待つまで未処理のPromise拒否があるでしょう。

私の言いたいことは、未処理のPromise拒否が問題であると考えると、後で待機によって処理されるPromiseが誤ってバグとして報告される可能性があるということです。それでも、未処理のPromise拒否が問題にならないと見なすと、正当なバグは報告されない可能性があります。

これについての考え?

これはNode.jsプロジェクトのディスカッションに関連しています。

デフォルトの未処理の拒否検出動作

あなたがこのようにコードを書くならば:

function getReadyForBed() {
  let teethPromise = brushTeeth();
  let tempPromise = getRoomTemperature();

  // Change clothes based on room temperature
  return Promise.resolve(tempPromise)
    .then(temp => {
      // Assume `changeClothes` also returns a Promise
      if (temp > 20) {
        return Promise.resolve(changeClothes("warm"));
      } else {
        return Promise.resolve(changeClothes("cold"));
      }
    })
    .then(teethPromise)
    .then(Promise.resolve()); // since the async function returns nothing, ensure it's a resolved promise for `undefined`, unless it's previously rejected
}

GetReadyForBedが呼び出されると、最後の(返されない)promiseが同期的に作成されます。これは、他のpromiseと同じ「未処理の拒否」エラーが発生します(もちろん、エンジンによっては何も起こり得ない)。 (あなたの関数が何も返さないというのは非常に奇妙なことです。つまり、あなたのasync関数は未定義の約束をするということです。

キャッチせずにPromiseを作成し、後でもう1つ追加すると、ほとんどの "未処理の拒否エラー"の実装は実際に警告を取り消します。言い換えれば、async/awaitは私が見ることができるように「未処理の拒否」の議論を変更することはありません。

この落とし穴を避けるために、このようにコードを書いてください:

async function getReadyForBed() {
  let teethPromise = brushTeeth();
  let tempPromise = getRoomTemperature();

  // Change clothes based on room temperature
  var clothesPromise = tempPromise.then(function(temp) {
    // Assume `changeClothes` also returns a Promise
    if(temp > 20) {
      return changeClothes("warm");
    } else {
      return changeClothes("cold");
    }
  });
  /* Note that clothesPromise resolves to the result of `changeClothes`
     due to Promise "chaining" magic. */

  // Combine promises and await them both
  await Promise.all(teethPromise, clothesPromise);
}

これにより、未処理の約束拒否が防止されるはずです。

19
anis programmer

"DeprecationWarning: 未処理 promise拒否は推奨されません"

TLDR:約束にはresolverejectがあります。それを処理するためにキャッチなしでrejectを実行することは推奨されないため、少なくとも最上位レベルにcatchが必要です。

9

私の場合、Promise関数は例外をスローしたため、リジェクトもリゾルブも解決しないPromiseでした。この間違いにより、UnhandledPromiseRejectionWarningメッセージが発生します。

0
Diniz

プロミスをインスタンス化すると、非同期関数が生成されます。もし機能がうまくいったら、私はRESOLVEを呼び出します、そしてフローはRESOLVEハンドラの中で続きます。機能が失敗した場合は、REJECTを呼び出して機能を終了し、その後フローはCATCHで続行されます。

NodeJでは、拒否ハンドラは非推奨です。あなたのエラーは単なる警告であり、私はnode.js githubの中でそれを読みました。私はこれを見つけました。

DEP0018:未処理の約束拒否

タイプ:ランタイム

未処理の約束拒否は非推奨です。将来的には、処理されない約束の拒否は、Node.jsプロセスをゼロ以外の終了コードで終了させるでしょう。

0
koλzar