NodeJS UnhandledPromiseRejectionWarning

所以,我正在testing一个依赖事件发生器的组件。 为此,我想出了一个使用Mocha + Chai的承诺的解决scheme:

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'

(节点:25754)UnhandledPromiseRejectionWarning:未处理的承诺拒绝(拒绝ID:2):AssertionError:承诺错误:期望{对象(消息,showDiff,…)}是虚假的1)应该过渡与正确的事件

然后,2秒后我得到

错误:超过2000毫秒超时。 确保在此testing中正在调用done()callback。

自从catchcallback被执行后,哪个更加怪异(我认为由于某种原因,assert失败阻止了其余的执行)

现在有趣的是,如果我注释掉assert.isNotOk(error...)testing运行正常,没有在控制台中的任何警告。 它在执行捕捉的意义上仍然是“失败”的。
但是,我仍然无法用承诺理解这些错误。 有人可以启发我吗?

这个问题是由这个原因造成的:

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

如果断言失败,它会抛出一个错误。 这个错误会导致done()永远不会被调用,因为代码在它之前出错了。 这是导致超时的原因。

“未处理的承诺拒绝”也是由失败的断言引起的,因为如果在catch()处理程序中抛出错误, 并且没有后续的catch()处理程序 ,则错误将被吞下(如本文所述 )。 UnhandledPromiseRejectionWarning警告提醒您这个事实。

一般来说,如果你想在摩卡中testing基于承诺的代码,你应该依靠摩卡本身已经可以处理承诺的事实。 你不应该使用done() ,而是从testing中返回一个promise。 摩卡会自己接收任何错误。

喜欢这个:

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

当与sinon沾边时,我得到了这个错误。

解决办法是使用npm包sinon-as-promise解决或拒绝带有存根的承诺。

代替 …

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

使用 …

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

还有一个解决方法(注意到结束)。

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

如果断言不正确,则Mocha中的断言库将通过抛出错误来工作。 抛出一个错误会导致被拒绝的承诺,即使抛出在提供给catch方法的执行器函数中。

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

在上面的代码中, error计算结果为true所以断言库会抛出一个错误…这是从未被捕获的错误。 作为错误的结果, done方法从不被调用。 摩卡donecallback接受这些错误,所以你可以简单地结束摩卡的所有承诺链。然后.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); }); 

我赞赏这篇文章中使用。然后(完成,完成)在摩卡testing承诺的想法。

我面临这个问题:

(node:1131004)UnhandledPromiseRejectionWarning:未处理的承诺拒绝(拒绝ID:1):TypeError:res.json不是函数(节点:1131004)DeprecationWarning:不build议使用未处理的承诺。 将来,未处理的承诺拒绝将以非零退出代码终止Node.js进程。

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

这里是我与E7asynchronous/等待的经验:

如果你有一个从你的testing中调用的async helperFunction() …(我用一个ES7 async关键字来表示)

→确保你把这个叫做await helperFunction(whateverParams) (好吧,当然,一旦你知道了…)

为了避免“等待是一个保留字”,你的testing函数必须有一个外部的asynchronous标记:

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