当前位置: 首页 > 知识库问答 >
问题:

在循环中使用fs.read文件的promise

谷梁玺
2023-03-14

我试图理解为什么下面的promise设置不起作用。

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

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

谢谢!

尝试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");
}

提前谢谢你的帮助!

共有3个答案

蓬高谊
2023-03-14

您的代码应该更像这样:

// 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一个函数意味着接受一个具有回调语义的异步函数,并从中派生一个具有promise语义的新函数。

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

房项禹
2023-03-14

节点v10有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

或者,如果要同时读取更多文件:

const func = filenames => {
  return Promise.all(
    filenames.map(f => fsPromises.readFile(f))
  )
}

func(['./a','./b'])
  .then(res => console.log('all read', res))
  .catch(console.log)
王才
2023-03-14

所以,只要您有多个异步操作要以某种方式进行协调,我马上就要转到Promissions。而且,使用promise来协调多个异步操作的最佳方法是使每个异步操作返回一个promise。显示的最低级别异步操作是fs.readFile()。因为我使用了Bluebird promise库,所以它有一个函数“promisify”整个模块的异步函数。

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

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

因此,现在您可以创建一个函数,该函数相当简单地获取图像,并返回一个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,您可以手动创建一个promise版本的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异步调用约定的函数的扩展版本:

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

不过,你会很快发现,一旦你开始使用promise,你就想在所有异步操作中使用它们,所以你会“promisiated”很多东西,并且有一个库或者至少一个通用函数来为你做这件事,这将节省很多时间。

在更新版本的node.js(10.0版)中,您可以使用内置版本的fs库,该库支持以下promise:

const fsp = require('fs').promises;

fsp.readFile("someFile").then(data => {
    console.log(data);
});
 类似资料:
  • 我想在Excel 2010中使用vba循环浏览目录的文件。 在循环中,我需要: 文件名和 我已经编写了以下代码,如果文件夹中的文件不超过50个,它就可以正常工作,否则速度会慢得离谱(我需要它来处理带有 工作但速度太慢的代码(每100个文件15秒): 问题解决: 我的问题已通过以下解决方案得到解决:以特定方式使用(15000个文件为20秒),并使用命令检查时间戳 考虑到下面的另一个答案,20秒缩短为

  • 我使用的php foreach语句如下所示:

  • 问题内容: 在连接到仓库以及添加,提交甚至循环提交文件的消息方面,我已经设法掌握了jGit文件的基础知识。 我接下来要做的是能够获取单个文件的所有提交消息,然后能够将单个文件还原回特定的参考/时间点。 问题答案: 这是基于所有父提交查找提交更改的方法 (标量代码) 请注意,TreeFilter.ANY_DIFF适用于单个树遍历器,并将返回根提交中可用的所有元素。 然后,您将不得不遍历树以查看您的文

  • 如何更改下面的代码来查看目录中的所有.log文件,而不是只查看一个文件? 我需要循环遍历所有文件,删除所有不包含“step4”或“step9”的行。目前,这将创建一个新文件,但我不确定如何在这里使用循环(newbie)。

  • 我想创建一个场景,在这个场景中我想使用来自jar文件的数据到Jmeter循环逻辑中。 我的罐子看起来像: 1)有了上面的数据,我想像贝娄图片中描述的那样“feed”Jmeter调用 2)每当我在jar文件中添加新的国家时,循环就会相应地增加。 有些人想如何做到这一点,我应该用什么作为变量,我如何告诉循环增加?

  • 可能的重复: 如何从文件的内容 整个文本文件创建Java字符串 我正在尝试使用FileReader读取文件的内容。但是我不想逐行读文件。是否可以不循环地读取整个文件。我正在使用以下代码