我最近在执行node.js文件时遇到了问题。 我将发布代码并解释问题所在。
我有两个文件,即testit.js和test.js
在test.js中,我使用module.exports将包含textfiles文件路径的数组对象传递给testit.js
["a.txt","b.txt"]
在testit.js中,module.exports.text接受文件名的数组对象,
通过Object.keys(texts).forEach
,
处理每一个
通过readFile
,
读取每个返回的缓冲区值
通过takeAction
返回包含在该缓冲区中的文本
并将其存储在数组对象newtexts
中。
但是当newtexts被解析并且调用返回到then()时,在命令行上打印newtexts,它返回 EMPTY ARRAY OBJECT 而不是返回每个文件内容的数组对象那些文件。
有人能解释一下我在代码中出错了吗? 非常感谢。
test.js
var testit = require('./testit');
var texts = ["a.txt","b.txt"];
testit.text(texts).then(function(newtexts){
console.log(newtexts);
});
testit.js
var Promise = require('bluebird');
var S = require('string');
var fs = require("fs");
module.exports.text = function(text){
var texts = text;
var length = Object.keys(texts).length;
return new Promise(function(resolve, reject){
var newtexts = [];
var takeAction = function(text) {
return text.toString();
}
var readFile = function (filename, enc){
return new Promise(function (resolve, reject){
fs.readFile(filename, enc, function (err, buffer){
if(err)
reject(err);
else
resolve(buffer);
});
});
}
Object.keys(texts).forEach(function(key){
readFile(texts[key]).then(function(text){
newtexts[key] = takeAction(text);
});
});
resolve(newtexts);
});
}
答案 0 :(得分:2)
在解决整体Promise之前,您需要等待所有readFile Promises解决。
替换
Object.keys(texts).forEach(function(key){
readFile(texts[key]).then(function(text){
newtexts[key] = takeAction(text);
});
});
resolve(newtexts);
有这样的事情:
var textPromises = texts.map( function (fileName) {
return readFile(fileName).then( function (text) {
newtexts[fileName] = takeAction(text);
});
});
Promise.all(textPromises).then( function () {
resolve(newtexts);
});
这里的基本思想是将每次调用readFile返回的Promise存储到一个数组中(或者更确切地说,我们存储一个在readFile完成后解析并在结果处理并存储到newtexts之后解析的Promise),并且只有当数组中的所有Promise都已解析时,我们将解析从此函数返回的promise。
答案 1 :(得分:0)
@pmv现在您提到了Promise.all和.map,现在这一切都很有意义。为了更好地理解这一点,我在takeAction
重新修改了代码以返回Promise
:
var takeAction = function (text) {
return new Promise( function (resolve,reject){
resolve(text.toString());
});
}
以及在返回readFile
之后的textPromises内部:
var textPromises = texts.map( function (fileName) {
return readFile(fileName).then( function (buffer) {
//newtexts[fileName] = takeAction(text);
return takeAction(buffer).then(function (text){
newtexts[text] = text;
});
});
});
以下是结果的屏幕截图: SS of the result
非常感谢您的帮助:)
答案 2 :(得分:0)
不必要的承诺值得避免,因为它们是昂贵的操作。您可能想考虑以下问题:
new Promise()
包装器是不必要的,因为您可以返回Promise.all(promises)...
返回的承诺。这不仅会消除不必要的承诺,还会允许错误传播给调用者。请注意,在您自己的代码中,永远不会调用外部承诺reject
。takeAction()
返回新承诺会使效率降低两倍;首先需要创建一个promise,然后需要另一个.then()(因此还有另一个promise)来访问结果。如果操作是同步的,请尝试使它们保持同步。.then()
的同步处理转换为.map()
(适当地重命名),可以完全避免buffer
循环中的readFile()
。同样,保持同步操作同步。试试这个:
module.exports.text = function (fileNames) {
var newtexts = {}; // <<<<<<< Object not Array.
function takeAction(key, buffer) { // <<<<<<< takeAction now accepts key and buffer
newtexts[key] = buffer.toString(); // <<<<<<< make the assignment here
}
function readFileAndTakeAction(key) {
return new Promise(function (resolve, reject) {
fs.readFile(filenames[key], null, function (err, buffer) {
if(err) {
reject(err);
} else {
takeAction(key, buffer); // <<<<<<< by doing this here, you avoid an extra .then() elsewhere.
resolve();
}
});
});
}
var promises = Object.keys(fileNames).map(readFileAndTakeAction);
// Instead of resolving an outer promise, return Promise.all(...).then(...)
return Promise.all(promises).then(function () {
return newtexts;
});
}
将readFile()
从fs.readFile()
的通用推广者转变为专家可能会掠夺一些优雅的代码,但肯定会提高效率。此外,.map(readFileAndTakeAction)
的优雅不仅仅是补偿。