为什么Promise在Node.js中返回(parsing)一个空对象?

我最近在执行node.js文件时遇到了问题。 我将发布代码并解释问题所在。

我有2个文件,即testit.js和test.js

在test.js中,我使用module.exports将包含文本文件的文件path的数组对象传递给testit.js

["a.txt","b.txt"] 

在testit.js中,module.exports.text接受文件名的数组对象,
通过Object.keys(texts).forEach处理每个Object.keys(texts).forEach
通过readFile读取每个返回的缓冲区值,
通过takeAction返回包含在该缓冲区中的文本
并将其存储在数组对象newtexts

但是,当newtexts被parsing并且调用返回到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); }); } 

在解决整体承诺之前,您需要实际等待所有readFile承诺解决。

更换

  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存储到一个数组中(更确切地说,我们存储一个Promise,在readFile完成后处理并存储到newtext中),并且只有当所有数组中的Promise已经解决了,我们解决了从这个函数返回的诺言。

@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

十分感谢你的帮助 :)

不必要的承诺是值得避免的,因为它们是昂贵的操作。 您可能想要考虑以下问题:

  • new Promise()包装器是不必要的,因为你可以返回Promise.all(promises)...返回的promise。 这不仅会摆脱不必要的承诺,还会让错误传播给调用者。 请注意,在您自己的代码中,外部承诺的reject从不会被调用。
  • takeAction()返回一个新的承诺会使效率减less两倍; 首先需要创build一个承诺,其次需要另一个.then()(因此还有另一个承诺)来访问结果。 如果操作是同步的,请尽量保持同步。
  • 那么.map()循环中的.then() s可以通过将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; }); } 

fs.readFile()的通用promisifier中的fs.readFile()变成专家,可以说是盗取了一些优雅的代码,但肯定会提高效率。 除此之外, .map(readFileAndTakeAction)的优雅还不止.map(readFileAndTakeAction)