JS:优雅的方式来等待回调完成
在我的节点应用程序中,我需要产生多个文件写入并等待它们完成,然后再继续处理其他内容。我已经通过以下方式实现了这一点:JS:优雅的方式来等待回调完成
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();
虽然它按需运作,但我觉得可能有一些更好的习语。有什么建议么?
尽管它按照我们的期望工作,但我觉得可能有一些更好的习语。
这是承诺的目的之一。下面是与承诺改写代码(故能走的更远,还有库诺 - IFY的NodeJS的API):
let operations = []
(some loop declaration) {
// (preparing data etc)
operations.push(new Promise((resolve, reject) => {
fs.writeFile(fname, fdata, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
}));
}
Promise.all(operations).then(() => {
// All done
});
或者考虑一下,如果我们的writeFile
一诺指明分数版本:
let operations = []
(some loop declaration) {
// (preparing data etc)
operations.push(writeFileWithPromise(fname, fdata));
}
Promise.all(operations).then(() => {
// All done
});
,或者如果“循环”是在一个迭代,我们可以变成一个数组,并使用map
:
Promise.all(
Array.from(theThingy).map(entry => writeFileWithPromise(entry.fname, entry.fdata))
).then(() => {
// All done
});
@Benjamin:再次感谢您!但'Array.from'是必须的,因为我们需要在迭代器上调用'map'(我们没有直接将它传递给'Promise.all')。 –
使用异步:
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的非常知名的库。
以下是您可以对您的案例进行的操作。下面是它会采用并行处理是什么样的一个基本方式:
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
}
);
如果你想在任务运行一个一个为了您将使用async.series。如果您希望函数将结果传递给下一个任务,则可以使用async.waterfall。当然,还有其他功能可以使用,但我提到的功能是一些非常常见的功能。
我已经尝试了承诺,我不完全相信,有多大的优势,利用他们在做这样的事情:
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(),当每个操作完成时,我检查计数器的值。
IMO,这是一样有效,也许更容易阅读。
或者,如果你不喜欢有一个单独的函数来完成了......
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
}
});
}
最后我还是得到一个函数调用,而不是继续在同一个范围内的代码流。 –
@Vadim,当然,但它不一定是一个单独的功能。我添加了一个替代品。实际上,done()与Promise.all(ops).then()几乎相同,除非不必管理promise对象。 – Octopus
承诺和'Promise.all' – zerkms
常量writeFileP =需要( '蓝鸟')。promisify(FS。 writeFile); // writeFileP(...)返回一个承诺 – brainjam