我正在尝试编写一个自定义的mocha报告器,该报告器与具有HTTP API的第三方集成。
我采用了自定义报告者(https://github.com/mochajs/mocha/wiki/Third-party-reporters)给出的基本示例,并尝试在启动事件处理程序中添加对API的调用。但是,我对第三方的http请求的回调似乎从未触发过。示例代码如下所示。
我已经测试过请求代码在其他上下文中按预期工作,它似乎只是在mocha记者的事件处理程序中没有任何反应。
注意 - 请原谅当前黑客等待回调的结果,我只是想确保在回调有机会开火之前我没有退出,当我开始工作时我会整理一下!
var request = require('request');
module.exports = function (runner) {
var passes = 0;
var failures = 0;
runner.on('start', function() {
var callbackFired = false;
request('http://www.testapi.com', function (error, response, body) {
callbackFired = true;
});
while(!callbackFired){
console.log('waiting...');
}
});
runner.on('pass', function(test){
passes++;
console.log('pass: %s', test.fullTitle());
});
runner.on('fail', function(test, err){
failures++;
console.log('fail: %s -- error: %s', test.fullTitle(), err.message);
});
runner.on('end', function(){
console.log('end: %d/%d', passes, passes + failures);
process.exit(failures);
});
};
答案 0 :(得分:2)
你的回调永远不会执行,因为你的代码没有给它机会执行。你有一个基本原则,你不了解JavaScript或者你暂时忘记了: JavaScript代码是没有被抢先。这段代码保证是一个无限循环:
while(!callbackFired){
console.log('waiting...');
}
为什么呢?首先,因为request
必须在callbackFired
成为真之前实际完成HTTP请求。当你调用request
时,它所做的是启动HTTP请求并记录当请求完成时,应该调用回调。第二,记得我说上面没有先发制人? JavaScript VM在callbackFired
变为true之前进入循环,并开始执行循环。在循环执行时,HTTP请求可能会完成,但回调仍然将不会执行。为什么?因为只要循环正在执行(无抢占!),JavaScript VM就无法控制回调。为了使VM能够控制回调,您的代码必须返回,以便最终由VM启动的所有函数都返回,然后VM有机会处理HTTP完成。
以更正式的术语(请参阅documentation here,您的代码不会为VM的事件循环提供机会来处理HTTP完成事件并控制您的回调。
话虽如此,还有其他考虑因素让您的记者异步工作:
请勿向您的记者致电process.exit
。如果您在流程退出时需要执行某些操作,则可以使用process.on('exit', ...
。
事件处理程序同步运行,因此您不能让runner.on('start', ...)
等待异步操作的结果。
您可以做的是让runner.on('start', ...)
启动一个返回promise的异步操作,然后在runner.on('pass', ...)
(和'fail'
)中使用此promise来执行更多的异步操作。例如,
module.exports = function (runner) {
var passes = 0;
var failures = 0;
var init;
runner.on('start', function() {
init = async_op_returning_promise(...);
});
runner.on('pass', function(test){
passes++;
init.then(function (results) {
// do something more...
});
});