假设您需要执行一些依赖于某些临时文件的操作。既然我们在这里谈论Node,那么这些操作显然是异步的。为了知道何时可以删除临时文件,等待所有操作完成的惯用方式是什么?
这是一些代码,显示我想做什么:
do_something(tmp_file_name, function(err) {}); do_something_other(tmp_file_name, function(err) {}); fs.unlink(tmp_file_name);
但是,如果我这样编写,则可以在前两个调用有机会使用该文件之前执行第三个调用。我需要某种方法来确保前两个调用在结束之前已经完成(调用了它们的回调),而没有嵌套这些调用(并使它们在实践中保持同步)。
我考虑过在回调上使用事件发射器,并将计数器注册为接收器。计数器将接收已完成的事件并计算仍有多少操作待处理。当最后一个完成时,它将删除该文件。但是存在比赛条件的风险,我不确定这通常是如何完成的。
Node人员如何解决此类问题?
更新:
现在,我建议看一下:
Promise对象用于延迟和异步计算。Promise表示尚未完成的操作,但有望在将来进行。
一个流行的承诺库是蓝鸟。A建议看看为什么答应。
您应该使用promise来解决这个问题:
> > fs.readFile("file.json", function (err, val) { > if (err) { > console.error("unable to read file"); > } > else { > try { > val = JSON.parse(val); > console.log(val.success); > } > catch (e) { > console.error("invalid json in file"); > } > } > });
变成这个:
> > fs.readFileAsync("file.json").then(JSON.parse).then(function (val) > { > console.log(val.success); > }) > .catch(SyntaxError, function (e) { > console.error("invalid json in file"); > }) > .catch(function (e) { > console.error("unable to read file"); > });
使用Promise,基于Node.js和浏览器的基于生成器的控制流优势,可让您以一种不错的方式编写非阻塞代码。
> > var co = require('co'); > > co(function *(){ > // yield any promise > var result = yield Promise.resolve(true); > }).catch(onerror); > > co(function *(){ > // resolve multiple promises in parallel > var a = Promise.resolve(1); > var b = Promise.resolve(2); > var c = Promise.resolve(3); > var res = yield [a, b, c]; > console.log(res); > // => [1, 2, 3] > }).catch(onerror); > > // errors can be try/catched > co(function *(){ > try { > yield Promise.reject(new Error('boom')); > } catch (err) { > console.error(err.message); // "boom" > } > }).catch(onerror); > > function onerror(err) { > // log any uncaught errors > // co will not throw any errors you do not handle!!! > // HANDLE ALL YOUR ERRORS!!! > console.error(err.stack); > }
如果我理解正确,我想您应该看一下非常好的异步库。您应该特别看一下该系列。只是来自github页面的摘录的一个副本:
async.series([ function(callback){ // do some stuff ... callback(null, 'one'); }, function(callback){ // do some more stuff ... callback(null, 'two'); }, ], // optional callback function(err, results){ // results is now equal to ['one', 'two'] }); // an example using an object instead of an array async.series({ one: function(callback){ setTimeout(function(){ callback(null, 1); }, 200); }, two: function(callback){ setTimeout(function(){ callback(null, 2); }, 100); }, }, function(err, results) { // results is now equals to: {one: 1, two: 2} });
另外,该库还可以在浏览器中运行。