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
方法从不被调用。 摩卡done
callback接受这些错误,所以你可以简单地结束摩卡的所有承诺链。然后.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 () => { ...