在循环中使用带fs.readFile的Promise

我想了解为什么下面的承诺设置不起作用。

(注意:我已经用async.map解决了这个问题,但是我想知道为什么我的下面的尝试不起作用。)

正确的行为应该是:bFunc应该运行尽可能多的时间fs读取所有的图像文件(bFunc下面运行两次),然后cFunc控制台打印“结束”。

谢谢!

尝试1:它运行并停在cFunc()。

var fs = require('fs'); bFunc(0) .then(function(){ cFunc() }) //cFunc() doesn't run function bFunc(i){ return new Promise(function(resolve,reject){ var imgPath = __dirname + "/image1" + i + ".png"; fs.readFile(imgPath, function(err, imagebuffer){ if (err) throw err; console.log(i) if (i<1) { i++; return bFunc(i); } else { resolve(); }; }); }) } function cFunc(){ console.log("End"); } 

尝试2:在这种情况下,我使用了一个for循环,但它不按顺序执行。 控制台打印:结束,bFunc完成,bFunc完成

 var fs = require('fs'); bFunc() .then(function(){ cFunc() }) function bFunc(){ return new Promise(function(resolve,reject){ function read(filepath) { fs.readFile(filepath, function(err, imagebuffer){ if (err) throw err; console.log("bFunc done") }); } for (var i=0; i<2; i++){ var imgPath = __dirname + "/image1" + i + ".png"; read(imgPath); }; resolve() }); } function cFunc(){ console.log("End"); } 

我在这里先向您的帮助表示感谢!

所以,只要你有多个asynchronous操作以某种方式进行协调,我立刻就想去承诺。 而且,使用promise来协调一些asynchronous操作的最好方法是让每个asynchronous操作返回一个promise。 您显示的最低级asynchronous操作是fs.readFile() 。 由于我使用蓝鸟承诺库,它具有“promisifying”整个模块的asynchronousfunction价值的function。

 var Promise = require('bluebird'); var fs = Promise.promisifyAll(require('fs')); 

这将在fs对象上创build新的并行方法,使用“Async”后缀来返回promise,而不是使用直接callback。 所以,会有一个fs.readFileAsync()返回一个promise。 你可以在这里阅读更多关于蓝鸟的promisification。

所以,现在你可以做一个函数来获得一个图像相当简单,并返回一个承诺的价值是来自图像的数据:

  function getImage(index) { var imgPath = __dirname + "/image1" + index + ".png"; return fs.readFileAsync(imgPath); } 

然后,在你的代码中,看起来你想让bFunc()成为一个函数,读取这些图像中的三个,并在完成时调用cFunc() 。 你可以这样做:

 var Promise = require('bluebird'); var fs = Promise.promisifyAll(require('fs')); function getImage(index) { var imgPath = __dirname + "/image1" + index + ".png"; return fs.readFileAsync(imgPath); } function getAllImages() { var promises = []; // load all images in parallel for (var i = 0; i <= 2; i++) { promises.push(getImage(i)); } // return promise that is resolved when all images are done loading return Promise.all(promises); } getAllImages().then(function(imageArray) { // you have an array of image data in imageArray }, function(err) { // an error occurred }); 

如果你不想使用蓝鸟,你可以像这样手工制作fs.readFile()的承诺版本:

 // make promise version of fs.readFile() fs.readFileAsync = function(filename) { return new Promise(function(resolve, reject) { fs.readFile(filename, function(err, data){ if (err) reject(err); else resolve(data); }); }); }; 

虽然,你会很快发现,一旦你开始使用承诺,你想使用它们进行所有的asynchronous操作,所以你将“promisifying”很多东西,并有一个库或至less一个通用的function,将为你做节省很多时间。

你的代码应该看起来更像这样:

 var fs = require('fs'); var __dirname = "foo"; // promisify fs.readFile() fs.readFileAsync = function (filename) { return new Promise(function (resolve, reject) { try { fs.readFile(filename, function(err, buffer){ if (err) reject(err); else resolve(buffer); }); } catch (err) { reject(err); } }); }; // utility function function getImageAsync(i) { return fs.readFileAsync(__dirname + "/image1" + i + ".png"); } 

使用单个图像:

 getImageAsync(0).then(function (imgBuffer){ console.log(imgBuffer); }).catch(function (err) { console.error(err); }); 

用于多个图像:

 var images = [1,2,3,4].map(getImageAsync); Promise.all(images).then(function (imgBuffers) { // all images have loaded }).catch(function (err) { console.error(err); }); 

promisify函数意味着采取与callback语义asynchronousfunction,并从它派生一个新的function与承诺的语义。

它可以手动完成,如上所示,或者 – 最好 – 自动完成。 其中,蓝鸟承诺库有一个帮手,请参阅http://bluebirdjs.com/docs/api/promisification.html