我有以下希望测试的函数,其中大量使用async.js:
MyClass.prototype.pipeline = function(arg1, arg2) {
...
async.waterfall([
async.apply(self.a.f.bind(self.a), arg1, arg2),
function(data, callback) {
async.each(data, function(d, callback) {
async.waterfall([
async.apply(self.b.f.bind(self.b), d),
self.c.f.bind(self.c),
self.d.f.bind(self.d),
self.e.f.bind(self.f)
], function(err, results) {
if (err) {
...
}
callback();
});
}, function(err) {
callback(err, data);
});
}
], function (err, result) {
...
});
};
现在我知道我可以把很多在这里发生的事情分开来分离各种功能,但它是在前一个完成后将数据相互传递的简化动作的管道,所以我希望保持它像这样,例如将函数function(data, callback) {...}
与BCDEpipeline这样的名称分开。
无论如何,我的问题是我根据第一个async.waterfall()
完成函数的完成回调做了一些断言,问题是它后来被调用(延迟),即使我存在a,b,c,d和e函数已经让他们立即产生下一个回调。请注意,我不能只是存根async.waterfall()
并使其完成回调,因为我将留下未经测试的关键代码分支(async.each()
的内部完成回调和第二个async.waterfall()
。
我尝试使用sinon假定时器并在调用this.clock.tick(0);
函数之后使用MyClass.prototype.pipeline()
,如下所示:
var obj = new MyClass();
obj.pipeline(5, 3);
this.clock.tick(0);
/* assertions */
...
但即便如此,在调用任何完成函数之前,部分正在被执行。我试图深入研究异步库代码,看看它是如何调用它的完成函数的,这太令人头疼了,我无法弄清楚为什么即使完成的回调调用都是延迟的并且与sinon一起假定时器,我的断言代码仍在执行。
如果我使用一些嵌套的setImmediate()
调用它可以正常工作,但这是解决此问题的最差解决方案。
答案 0 :(得分:0)
你遗漏了很多东西,所以很难分辨出这应该做些什么。老实说,这听起来像是噪音,虽然这不是你的错。
如果你实际上并不需要并行执行大量的IO,那么这就是我的建议。切换到ES2017和babel。使用带有@autobind的类或类似的语法:
def contin():
con = input("Do you want to continue (Y/N):")
if con == 'y' or con == 'Y':
return menu()
else:
然后使用class Test {
constructor(testB) {
this.testB = testB;
}
fuzz = async x => x+1;
async foo = (bar) => {
try {
const result = await this.testB.blah(bar);
return await this.fuzz(result);
} catch (e) {
console.error(e);
return null;
}
}
async fizz = (bars) => await Promise.all(bars.map(this.foo));
}
进行测试。通过这种方式,您可以通过循环和异步测试来处理异步函数的基本流程(ava
),以及您的方法' await
将始终指向您的实例。
答案 1 :(得分:0)
好吧,根据以下问题我觉得这是旧版本的错误:
https://github.com/caolan/async/issues/609
https://github.com/caolan/async/issues/106
虽然它们已经很老了,而且我使用的是较新版本,但我刚刚更新了我的依赖项,现在它正常运行。