Node.js 在循环中使用带有fs.readFile的承诺
我试图理解为什么下面的承诺设置不起作用 (注意:我已经用async.map解决了这个问题。但是我想知道为什么我下面的尝试不起作用。) 正确的行为应该是:bFunc应该运行尽可能多的时间来读取所有映像文件(下面的bFunc运行两次),然后cFunc控制台打印“End” 谢谢 尝试1:它在cFunc()处运行并停止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){ 返回新承诺(功能(解决
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的例子,它更适合异步服务器