为什么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)
。