Javascript JS:等待回调完成的优雅方式
在我的节点应用程序中,我需要生成多个文件写入,并等待它们完成,然后再进行其他操作。我通过以下方式实现了这一点:Javascript JS:等待回调完成的优雅方式,javascript,node.js,Javascript,Node.js,在我的节点应用程序中,我需要生成多个文件写入,并等待它们完成,然后再进行其他操作。我通过以下方式实现了这一点: let counter = 0; (some loop declaration) { // (preparing data etc) counter += 1; fs.writeFile(fname, fdata, (err) => { counter -= 1; }); } let waitForCallbacks = funct
let counter = 0;
(some loop declaration) {
// (preparing data etc)
counter += 1;
fs.writeFile(fname, fdata, (err) => {
counter -= 1;
});
}
let waitForCallbacks = function() {
if (fcounter > 0) {
setTimeout(waitForCallbacks, 0);
}
};
waitForCallbacks();
虽然它能按预期工作,但我觉得可能会有更好的习惯用法。有什么建议吗
虽然它能按预期工作,但我觉得可能会有更好的习惯用法
这是承诺的目的之一。下面是用承诺重写的代码(它可以更进一步,有libs来承诺ifynodejsapi):
或考虑如果我们有一个允诺版本的<代码>写文件< /代码>:
let operations = []
(some loop declaration) {
// (preparing data etc)
operations.push(writeFileWithPromise(fname, fdata));
}
Promise.all(operations).then(() => {
// All done
});
或者,如果“循环”在一个iterable上,我们可以将其转换为一个数组,并在上使用map
:
Promise.all(
Array.from(theThingy).map(entry => writeFileWithPromise(entry.fname, entry.fdata))
).then(() => {
// All done
});
使用异步:
async.map([['name1', 'data1'], ['name2', 'data2'], ['name3', 'data3']],
function (item, cb) {
fs.writeFile(item[0], item[1], (err, res) => {
callback(err, res);
});
},
function(err, results) {
// results is now an array of results
});
承诺是一种方式。然而,如果你不喜欢它们,你可以使用一个非常有名的图书馆,叫做 这是你能为你的案子做的。下面是使用并行处理的基本方式:
async.parallel([
function(done) {
fs.writeFile(fname1, fdata1, (err) => {
done(err, customResults1);
});
},
function(done) {
fs.writeFile(fname2, fdata2, (err) => {
done(err, customResults2);
});
}
],
// The callback when every function above is done
function(err, results) {
// `results` contains a collection of what you've passed
// on the `done` callbacks above
});
为了更具体地针对您的用例,它将如下所示:
async.parallel(
['file1', 'file2'].map(function(fname) {
return function(done) {
fs.writeFile(fname, fdata, (err) => {
done(err, customResults);
});
};
}),
// The callback when every function above is done
function(err, results) {
// `results` contains a collection of what you've passed
// on the `done` callbacks above
}
);
如果希望任务按使用顺序逐个运行。如果希望函数将其结果传递给下一个任务,可以使用。当然,您还可以使用其他功能,但我提到的是一些非常常见的功能。我曾尝试过承诺,但我并不完全相信使用它们比执行类似操作有多大优势:
let counter = 0;
(some loop declaration) {
// (preparing data etc)
counter += 1;
fs.writeFile(fname, fdata, (err) => {
counter -= 1;
if ( counter==0 ) done()
});
}
function done(){
// that's it
}
与初始代码非常类似,除了不使用setTimeout()之外,我在每个操作完成时检查计数器的值
依我看,这同样有效,也许更容易阅读
或者,如果你不喜欢有一个单独的功能来完成
let counter = 0;
(some loop declaration) {
// (preparing data etc)
counter += 1;
fs.writeFile(fname, fdata, (err) => {
counter -= 1;
if ( counter==0 ) {
// that's it, finish up
}
});
}
promisify(fs.writeFile);//writeFileP(…)返回一个promiseYes,您推荐了一个外部库,但没有必要的原因。承诺很好地解决了这个问题,并且是内在的。这是一个写得很好的答案,但鉴于JS中异步操作的当前状态,我不认为它有用。OP没有说他不想使用外部库。是的,在这种情况下不需要一个。在不需要外部依赖的地方引入外部依赖对我来说似乎是不必要的。caolan/async在几年前是一个重要的库,但现在它大多已成为过去。我认为向新用户推荐它是对他们的伤害。当库仍在积极维护时,它怎么会成为过去呢?它最终还是以一个函数调用结束,而不是在相同的范围内继续代码流。只有一个回调而不是多个回调。我最终还是得到了一个函数调用,没有在同一个范围内继续代码流。@Vadim,当然,但它不必是一个单独的函数。我添加了一个替代方案。事实上,done()实际上与Promise.all(ops.then()相同,只是不需要管理Promise对象。@Benjamin:再次感谢您!但是
数组.from
是必需的,因为我们需要在iterable上调用映射(我们不会将它直接传递到Promise.all
)。
let counter = 0;
(some loop declaration) {
// (preparing data etc)
counter += 1;
fs.writeFile(fname, fdata, (err) => {
counter -= 1;
if ( counter==0 ) {
// that's it, finish up
}
});
}