首页 文章

NodeJS UnhandledPromiseRejectionWarning

提问于
浏览
93

所以,我正在测试一个依赖于事件 Launcher 的组件 . 为此,我想出了一个使用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();
    });
  });
});

在控制台上我得到一个'UnhandledPromiseRejectionWarning',即使拒绝函数被调用,因为它立即显示消息'AssertionError:Promise error'

(node:25754)UnhandledPromiseRejectionWarning:未处理的promise拒绝(拒绝id:2):AssertionError:Promise错误:expect {Object(message,showDiff,...)}是假的1)应该转换为正确的事件

然后,在2秒后我得到了

错误:超出2000毫秒的超时 . 确保在此测试中调用done()回调 .

自从执行catch回调以来,这甚至更奇怪 . (我认为由于某种原因,断言失败阻止了其余的执行)

现在有趣的是,如果我注释掉 assert.isNotOk(error...) ,测试运行正常,没有控制台中的任何警告 . 它仍然是'fails',因为它执行了捕获 .
但是,我仍然无法理解这些错误 . 有人可以开导我吗?

6 回答

  • 9

    问题是由此造成的:

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

    如果断言失败,则会抛出错误 . 此错误将导致 done() 永远不会被调用,因为代码在它之前出错了 . 这就是造成超时的原因 .

    "Unhandled promise rejection"也是由失败的断言引起的,因为如果在 catch() 处理程序中抛出错误,并且没有后续的 catch() 处理程序,则会吞下错误(如this article中所述) . UnhandledPromiseRejectionWarning 警告提醒您注意这一事实 .

    一般来说,如果你想在Mocha中测试基于promise的代码,你应该依赖Mocha本身已经可以处理promise的事实 . 您不应该使用 done() ,而是从测试中返回一个承诺 . 然后摩卡会捕捉到任何错误 .

    像这样:

    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');
      });
    });
    
  • 0

    当与sinon衔接时我得到了这个错误 .

    解决方法是在解析或拒绝带存根的promises时使用npm package sinon-as-promised .

    代替 ...

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

    使用 ...

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

    还有一种解决方法(注意结尾处的s) .

    http://clarkdave.net/2016/09/node-v6-6-and-asynchronously-handled-promise-rejections

  • 2

    如果断言不正确,Mocha中的断言库通过抛出错误来工作 . 抛出错误会导致拒绝的承诺,即使在提供给 catch 方法的执行程序函数中抛出也是如此 .

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

    在上面的代码中, error objected的计算结果为 true ,因此断言库会抛出一个错误...它永远不会被捕获 . 由于错误, done 方法永远不会被调用 . Mocha的 done 回调接受这些错误,因此您可以使用 .then(done,done) 简单地结束Mocha中的所有承诺链 . 这确保始终调用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);
    });
    

    我赞扬this article在mocha中测试promise时使用.then(done,done)的想法 .

  • 1

    对于那些在测试环境之外寻找错误/警告 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 函数中的第二个参数

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

    这是我对E7 async / await的体验:

    如果您从测试中调用了 async helperFunction() ...(我的意思是ES7 async 关键字的一个明确的)

    →确保,你称之为 await helperFunction(whateverParams) (嗯,是的,当然,一旦你知道......)

    为了实现这一目标(避免'await是一个保留字'),您的测试函数必须具有外部异步标记:

    it('my test', async () => { ...
    
  • 119

    我遇到了这个问题:

    (node:1131004)UnhandledPromiseRejectionWarning:未处理的promise拒绝(rejection id:1):TypeError:res.json不是函数(node:1131004)DeprecationWarning:不推荐使用未处理的promise promise . 将来,未处理的promise拒绝将使用非零退出代码终止Node.j进程 .

    这是我的错误,我正在 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
    }
    

相关问题