web-dev-qa-db-ja.com

NodeJS UnhandledPromiseRejectionWarning

だから、私はイベントエミッタに依存しているコンポーネントをテストしています。そのために、Promise with Mocha + Chaiを使った解決策を思いつきました。

it('should transition with the correct event', (done) => {
  const cFSM = new CharacterFSM({}, emitter, transitions);
  let timeout = null;
  let resolved = false;
  new Promise((resolve, reject) => {
    emitter.once('action', resolve);
    emitter.emit('done', {});
    timeout = setTimeout(() => {
    if (!resolved) {
      reject('Timedout!');
    }
    clearTimeout(timeout);
  }, 100);
}).then(((state) => {
      resolved = true;
      assert(state.action === 'DONE', 'should change state');
      done();
    }))
    .catch((error) => {
      assert.isNotOk(error,'Promise error');
      done();
    });
  });
});

拒否機能が即座に 'AssertionError:Promise error'というメッセージを表示するので、コンソールでは 'UnhandledPromiseRejectionWarning'を受け取ります。

(node:25754)UnhandledPromiseRejectionWarning:未処理のpromise rejection(拒否ID:2):AssertionError:Promiseエラー:{Object(message、showDiff、...)}は偽造されているはずです1)正しいイベントに遷移する

そして、2秒後に

エラー:2000msのタイムアウトを超えました。このテストでdone()コールバックが呼び出されていることを確認してください。

Catchコールバックが実行されてからずっと奇妙です(何らかの理由でassertの失敗が残りの実行を妨げたと思います)

面白いことに、assert.isNotOk(error...)をコメントアウトすると、テストはコンソールに何の警告もなく正常に実行されます。それは、それが捕獲を実行するという意味で、まだ「失敗」します。
しかしそれでも、私はこれらの間違いを約束して理解することはできません。誰かが私を悟らせることができますか?

105
Jzop

問題はこれによって引き起こされます:

.catch((error) => {
  assert.isNotOk(error,'Promise error');
  done();
});

アサーションが失敗すると、エラーが発生します。このエラーにより、done()が呼び出されることはなくなります。コードがエラーになる前にエラーが発生したためです。それがタイムアウトの原因です。

"Unhandled promise rejection" もアサーションの失敗によるものです。エラーがcatch()ハンドラでスローされた場合、 で、その後にcatch()ハンドラ がない場合、エラーは飲み込まれる( この記事 で説明されているように)。 UnhandledPromiseRejectionWarning警告はこの事実を警告しています。

一般的に、Mochaでpromiseベースのコードをテストしたい場合は、Mocha自体が既にPromiseを処理できるという事実に頼るべきです。 done()を使うべきではありませんが、代わりにあなたのテストからの約束を返してください。 Mochaはそれからどんなエラーでも捉えます。

このような:

it('should transition with the correct event', () => {
  ...
  return new Promise((resolve, reject) => {
    ...
  }).then((state) => {
    assert(state.action === 'DONE', 'should change state');
  })
  .catch((error) => {
    assert.isNotOk(error,'Promise error');
  });
});
129
robertklep

私がこの誤りを犯したのはsinonです。

修正はスタブで約束を解決するか拒絶するときnpmパッケージ sinon-as-promised を使うことです。

の代わりに ...

sinon.stub(Database, 'connect').returns(Promise.reject( Error('oops') ))

つかいます ...

require('sinon-as-promised');
sinon.stub(Database, 'connect').rejects(Error('oops'));

Resolvesメソッドもあります(最後のsに注意してください)。

http://clarkdave.net/2016/09/node-v6-6-and-asynchronously-handled-promise-rejection を参照してください。

9
danday74

Mochaのアサーションライブラリは、アサーションが正しくなかった場合にエラーをスローすることで機能します。エラーをスローすると、catchメソッドに提供されたexecutor関数でスローされた場合でも、拒否された約束が発生します。

.catch((error) => {
  assert.isNotOk(error,'Promise error');
  done();
});

上記のコードでは、却下されたerrortrueと評価されるため、アサーションライブラリはエラーをスローします。エラーの結果として、doneメソッドは呼び出されません。 Mochaのdoneコールバックはこれらのエラーを受け付けますので、Mochaのすべてのプロミスチェーンを.then(done,done)で終了させることができます。これにより、doneメソッドが常に呼び出され、Mochaが同期コードでアサーションのエラーを検出したときと同じ方法でエラーが報告されます。

it('should transition with the correct event', (done) => {
  const cFSM = new CharacterFSM({}, emitter, transitions);
  let timeout = null;
  let resolved = false;
  new Promise((resolve, reject) => {
    emitter.once('action', resolve);
    emitter.emit('done', {});
    timeout = setTimeout(() => {
      if (!resolved) {
        reject('Timedout!');
      }
      clearTimeout(timeout);
    }, 100);
  }).then(((state) => {
    resolved = true;
    assert(state.action === 'DONE', 'should change state');
  })).then(done,done);
});

この記事 はMochaでテストの約束をするときに.then(done、done)を使うという考えに敬意を表します。

8
Matthew Orlando

テスト環境の外でエラー/警告UnhandledPromiseRejectionWarningを探している人にとっては、おそらくコード内の誰もが約束の中で最終的なエラーの面倒を見ていないからでしょう。

たとえば、次のコードはこの質問で報告された警告を示します。

new Promise((resolve, reject) => {
  return reject('Error reason!');
});

(node:XXXX) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Error reason!

そして.catch()を追加するかエラーを処理することで警告/エラーを解決するはずです

new Promise((resolve, reject) => {
  return reject('Error reason!');
}).catch(() => { /* do whatever you want here */ });

あるいはthen関数の2番目のパラメータを使う

new Promise((resolve, reject) => {
  return reject('Error reason!');
}).then(null, () => { /* do whatever you want here */ });
4
gsalgadotoledo

これが E7 async/await の私の経験です。

テストからasync helperFunction()が呼び出された場合は...(ES7のasyncキーワードを使用した1つの解説)

→確かに、あなたはそれをawait helperFunction(whateverParams)と呼びます。

そしてそれが機能するためには(「待つことは予約語」を避けるため)、あなたのテスト関数は外側の非同期マーカーを持っていなければなりません:

it('my test', async () => { ...
1
Frank Nocke

私はこの問題に直面しました:

(node:1131004)UnhandledPromiseRejectionWarning:未処理のpromise rejection(拒否ID:1):TypeError:res.jsonは関数ではありません(node:1131004)DeprecationWarning:未処理のpromise rejectionは非推奨です。将来的には、処理されない約束拒否は、Node.jsのプロセスを0以外の終了コードで終了させるでしょう。

それは私の過ちでした。私はthen(function(res)内のresオブジェクトを置き換えていたので、resを結果に変更して今それは動作しています。

違う

module.exports.update = function(req, res){
        return Services.User.update(req.body)
                .then(function(res){//issue was here, res overwrite
                    return res.json(res);
                }, function(error){
                    return res.json({error:error.message});
                }).catch(function () {
                   console.log("Promise Rejected");
              });

補正

module.exports.update = function(req, res){
        return Services.User.update(req.body)
                .then(function(result){//res replaced with result
                    return res.json(result);
                }, function(error){
                    return res.json({error:error.message});
                }).catch(function () {
                   console.log("Promise Rejected");
              });

サービスコード:

function update(data){
   var id = new require('mongodb').ObjectID(data._id);
        userData = {
                    name:data.name,
                    email:data.email,
                    phone: data.phone
                };
 return collection.findAndModify(
          {_id:id}, // query
          [['_id','asc']],  // sort order
          {$set: userData}, // replacement
          { "new": true }
          ).then(function(doc) {
                if(!doc)
                    throw new Error('Record not updated.');
                return doc.value;   
          });
    }

module.exports = {
        update:update
}
0

Webpackをアンインストールした後、この問題を解決しました(react js problem)。

Sudo uninstall webpack
0
Mr Fun