当前位置:  开发笔记 > 编程语言 > 正文

在循环中使用带有fs.readFile的Promises

如何解决《在循环中使用带有fs.readFile的Promises》经验,为你挑选了3个好方法。

我试图理解为什么下面的承诺设置不起作用.

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

正确的行为应该是:bFunc应该运行尽可能多的时间来读取所有图像文件(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");
}

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



1> jfriend00..:

所以,只要你有多个异步操作以某种方式进行协调,我立即想要去承诺.并且,使用promises协调大量异步操作的最佳方法是使每个异步操作返回一个promise.您显示的最低级别异步操作是fs.readFile().由于我使用Bluebird promise库,它具有"宣传​​"整个模块的异步函数的功能.

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

这将在fs对象上创建新的并行方法,其后缀为"Async",返回promises而不是使用直接回调.所以,会有一个fs.readFileAsync()返回一个承诺.你可以在这里阅读更多关于蓝鸟的宣传的信息.

所以,现在你可以创建一个简单地获取图像的函数,并返回一个promise,其值是图像中的数据:

 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
 });

如果您不想使用Bluebird,您可以手动制作这样的承诺版本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);
        });
    });
};

或者,在node.js的现代版本中,您可以使用util.promisify()遵循node.js异步调用约定的函数的promisified版本:

const util = require('util');
fs.readFileAsync = util.promisify(fs.readFile);

虽然,你会很快发现,一旦你开始使用promises,你想要将它们用于所有异步操作,这样你就可以"宣传"很多东西,拥有一个库或至少一个通用函数来为你做这件事.节省大量时间.



2> Dmitry Yudak..:

Node v10具有Experimental fs Promises API

const fsPromises = require('fs').promises

const func = async filenames => {

  for(let fn of filenames) {
    let data = await fsPromises.readFile(fn)
  }

}

func(['file1','file2'])
  .then(res => console.log('all read', res))
  .catch(console.log)

https://nodejs.org/api/fs.html#fs_fs_promises_api


注意:自2019年6月28日起,此功能已稳定一段时间。

3> Tomalak..:

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

// promisify fs.readFile()
fs.readFileAsync = function (filename) {
    return new Promise((resolve, reject) => {
        fs.readFile(filename, (err, buffer) => {
            if (err) reject(err); else resolve(buffer);
        });
    });
};

const IMG_PATH = "foo";

// utility function
function getImageByIdAsync(i) {
    return fs.readFileAsync(IMG_PATH + "/image1" + i + ".png");
}

使用单个图像:

getImageByIdAsync(0).then(imgBuffer => {
    console.log(imgBuffer);
}).catch(err => {
    console.error(err);
});

使用多个图像:

var images = [1,2,3,4].map(getImageByIdAsync);

Promise.all(images).then(imgBuffers => {
    // all images have loaded
}).catch(err => {
    console.error(err);
});

promisify一个功能,就是要把有回调的语义异步函数,并承诺语义从中获得新的功能.

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

推荐阅读
爱唱歌的郭少文_
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有