未処理の約束拒否とは何ですか?


203

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が起こったのか、そしてこの警告を取り除くために何を確認する必要があるのか​​を簡単に説明できますか?


2
この質問を逃した!この警告を表示して申し訳ありません。混乱を招きます。新しいNode.jsで実際に改善し、すぐに全体を改善しました!
Benjamin


@BenjaminGruenbaum、それはまだ修正されていますか?ノードv12.16.1で同じエラーが発生しました
Baby desta

1
@Babydestaよく、スタックトレースでより良いエラーを表示しますが、未処理の拒否でノードをクラッシュさせません。そのためには、おそらくPRを開く必要があります。
Benjamin Gruenbaum

回答:


200

このエラーの原因は、すべてのプロミスがプロミスの拒否を処理することが期待されている、つまり.catch(...)があるという事実にあります。以下のように、コードのpromiseに.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エンジンは未処理のプロミス拒否なしでプロミスとして扱います。


4
myFunc = myFunct.then...2番目の例を追加すると、動作するようです。
アインシュタイン2017年

あなたが最初の例と同じチェーンを再作成しているので、それが仕事に表示されます@einstein:var x = foo(); x = x.then(...); x = x.catch(...)
randomsock

4
@einstein非連鎖の例で、「何らかの理由でJavaスクリプトエンジンが未処理のプロミス拒否なしにプロミスとして処理する」と言った場合、.then(() => {...})これ処理していないもので例外がスローされる可能性があるためです。これを連鎖させるのと同じことをしているとは思いません。それは...ですか?
Simon Legg 2017

8
@DKG 2番目の点についてcatchは、の構文シュガーですthen(undefined, onRejected)。あなたはすでにmyfuncでthenを呼び出し、それがエラーを引き起こしたので、同じpromiseでthen(undefined、onRejected)を再び呼び出すことはありません。
Kevin Lee

1
どこを変える?私はイオンコルドバビルドandoridコマンドをヒットしたときにイオン3を使用していますが、このエラーが発生します。
Sagar Kodte

34

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

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

こちらもご覧ください


どこを変える?私はイオンコルドバビルドandoridコマンドをヒットしたときにイオン3を使用していますが、このエラーが発生します。
Sagar Kodte

この情報ではわかりにくい。最小限の複製を作成し、特定の状況について新しい質問を作成することをお勧めします。
ギュンターZöchbauer

私はそれに報奨金をオープンしました。それは見て下さいstackoverflow.com/q/48145380/5383669
サーガルKodte

22

プロミスは拒否された後で「処理」できます。つまり、キャッチハンドラを提供する前に、promiseの拒否コールバックを呼び出すことができます。書くことができるので、この動作は私にとって少し面倒です...

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

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

Node.jsの場合、これらの未処理のPromise拒否の処理と問題の報告についての話があります。これにより、ES7 async / awaitが表示されます。この例を考えてみましょう:

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が拒否された(エラー:歯磨き粉がなくなった!)とします。この場合、toothPromiseを待つまで、未処理のPromise拒否があります。

私のポイントはこれです...未処理のPromise拒否が問題であると考えると、後でawaitによって処理された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を作成し、後で追加すると、ほとんどの「未処理の拒否エラー」実装は、後で処理するときに実際に警告を撤回します。言い換えれば、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);
}

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


13

「DeprecationWarning:未処理のプロミス拒否は廃止されました」

TLDR:promiseにはとがresolveありrejectrejectそれを処理するためにcatchなしで行うことは非推奨であるため、少なくともcatchトップレベルにする必要があります。


2

私の場合、Promise関数は例外をスローしたため、拒否も解決もされていないPromiseでした。この間違いにより、UnhandledPromiseRejectionWarningメッセージが発生します。


1

promiseをインスタンス化するときに、非同期関数を生成します。関数がうまくいけば、RESOLVEを呼び出し、フローはRESOLVEハンドラー、THENに続きます。関数が失敗した場合、REJECTを呼び出して関数を終了し、フローはCATCHで続行します。

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

DEP0018:未処理の約束の拒否

タイプ:ランタイム

未処理のpromiseの拒否は廃止されました。将来、処理されないpromiseの拒否により、Node.jsプロセスがゼロ以外の終了コードで終了します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.