Node.js 在循环中使用带有fs.readFile的承诺

Node.js 在循环中使用带有fs.readFile的承诺,node.js,promise,readfile,Node.js,Promise,Readfile,我试图理解为什么下面的承诺设置不起作用 (注意:我已经用async.map解决了这个问题。但是我想知道为什么我下面的尝试不起作用。) 正确的行为应该是:bFunc应该运行尽可能多的时间来读取所有映像文件(下面的bFunc运行两次),然后cFunc控制台打印“End” 谢谢 尝试1:它在cFunc()处运行并停止 var fs=require('fs'); bFunc(0) .then(function(){cFunc()})//cFunc()不运行 函数bFunc(i){ 返回新承诺(功能(解决

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

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

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

谢谢

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

var fs=require('fs');
bFunc(0)
.then(function(){cFunc()})//cFunc()不运行
函数bFunc(i){
返回新承诺(功能(解决、拒绝){
var imgPath=uu dirname+“/image1”+i+“.png”;
fs.readFile(imgPath,函数(err,imagebuffer){
如果(错误)抛出错误;
控制台日志(i)

如果(i您的代码看起来更像这样:

// 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");
}
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
 });
// 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);
        });
    });
};
使用单个图像时:

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库有一个帮助器,请参见

,因此,每当您有多个异步操作需要以某种方式协调时,我都会立即转到promises。而且,使用promises来协调多个异步操作的最佳方法是是使每个异步操作返回一个承诺。您显示的最低级别异步操作是
fs.readFile()
。由于我使用Bluebird promise库,它有一个函数用于“承诺”整个模块的异步函数

var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
这将在
fs
对象上创建新的并行方法,并使用“异步”后缀返回承诺,而不是使用直接回调。因此,将有一个
fs.readFileAsync()
返回承诺。您可以阅读有关Bluebird promisification的更多信息

因此,现在您可以创建一个函数,该函数相当简单地获取图像,并返回一个承诺,其值是来自图像的数据:

 function getImage(index) {
     var imgPath = __dirname + "/image1" + index + ".png";
     return fs.readFileAsync(imgPath);
 }
然后,在您的代码中,似乎希望使
bFunc()
成为一个函数,该函数读取其中三个图像,并在完成后调用
cFunc()
。您可以这样做:

// 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");
}
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
 });
// 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的现代版本中,您可以使用创建遵循node.js异步调用约定的函数的预期版本:

const util = require('util');
fs.readFileAsync = util.promisify(fs.readFile);
尽管如此,您很快就会发现,一旦开始使用承诺,您希望将其用于所有异步操作,因此您将“承诺”许多事情,并且拥有一个库或至少一个通用函数来为您执行这些操作,这将节省大量时间


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

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

fsp.readFile("someFile").then(data => {
    console.log(data);
});

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

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

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)

您也可以使用此模块: “fs readfile承诺”

var readFile=require('fs-readFile-promise');
readFile(uuu dirname+/file1.txt',utf-8')。然后(函数(数据){
log(“文件名:”,数据)
返回readFile(uuu dirname+'/'+数据,'utf-8')
}).then(函数(数据1){
console.log('Content data:',data1)
}).catch(函数(err){
console.log(错误)

})
在尝试1中,您的
bFunc
错误处理程序在哪里?如果抛出错误,您将永远不会知道当前代码中的错误。此代码的目标是什么?请用文字描述您试图解决的问题,而不是仅向我们显示不符合您要求的代码。您的代码有很多问题因此,我宁愿从理解要解决的问题开始,而不是在不知道实际最终目标的情况下,试图对代码中的所有错误进行返工。@nils它不会在bFunc中抛出错误!但我想我应该在链的末尾加上一个标记。@jfriend00我去掉了代码的所有细节,只是将结构简化了问题是一样的,但如果有帮助的话,我使用微软的牛津项目进行面部检测,然后在每一项中都使用“.then”我用眼镜、帽子等来放大照片。我可以和你分享源代码。谢谢。好吧,从我们的角度考虑一下。你给我们两块不起作用的代码,问我们如何修复它们。但是,你从来没有真正描述过它们应该做什么(正确的行为是什么)。我们应该从出现故障的代码中猜测正确的行为是什么吗?请描述您希望从任一代码块中获得的理想和正确的行为。请注意,您现在必须使用
promisify.promisifyAll
而不是
promisify.promisify
注意节点8附带了它自己的promisify函数:
const{promisify}=require(“util”);const fs=require(“fs”);const readFile=promisify(fs.readFile);
@Daniel-使用
util.promisify()
在node.js的较新版本中作为一个选项已经在我的答案中。添加了关于node.js v10+中内置的fs promise支持的信息。@MzA-现在的标准方法是使用
fs.promises.readFile
的最后一个代码块。我将重新组织答案。我只是好奇为什么要使用函数fs.readFile()在try catch?回调中可以处理错误,对吗?很好!谢谢。`return function(){return new Promise(function(resolve,reject){try{fs.readFile`在Gulp4上对我有效注意:从2019-06-28起,此功能已经稳定了一段时间。信息很棒!虽然您的示例没有什么意义,因为文件是同步读取的,对吗?每个承诺都要等待解决,然后才会触发下一个承诺。@estani这样它就处于循环中;)但这里有另一个并行执行TKS的例子,它更适合异步服务器