为什么 Promise 在 Node.js 中返回(解析)一个空对象?
Why is Promise returning (resolve) an empty object in Node.js?
我最近 运行 在执行 node.js 文件时遇到问题。
我将 post 代码并解释问题所在。
我有 2 个文件,即 testit.js 和 test.js
在 test.js 中,我使用 module.exports
将包含文本文件文件路径的数组对象传递给 testit.js
["a.txt","b.txt"]
在testit.js中,module.exports.text接受一个文件名数组对象,
通过 Object.keys(texts).forEach
、
处理每一个
通过 readFile
、
读取每个返回的缓冲区值
returns 通过 takeAction
该缓冲区中包含的文本
并将其存储在数组对象 newtexts
.
中
但是当新文本被解析并调用 returns 到 then() 时,其中新文本正在命令行上打印,它 returns 一个 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);
});
}
在解决整个 Promise 之前,您实际上需要等待所有 readFile Promise 解决。
替换
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 return 存储到一个数组中(或者更准确地说,我们存储一个 Promise,它在 readFile 完成后和结果处理后解析,并且存储到 newtexts 中),并且只有当数组中的所有 Promise 都已解决时,我们才会从这个函数中解决 return 的承诺。
值得避免不必要的承诺,因为它们是昂贵的操作。您可能想考虑以下问题:
- 外部
new Promise()
包装器是不必要的,因为您可以 return return 由 Promise.all(promises)...
编辑的承诺。这不仅会摆脱不必要的承诺,还会将错误传播给调用者。请注意,在您自己的代码中,永远不会调用外部承诺的 reject
。
- 从
takeAction()
返回一个新的承诺会降低两倍以上的效率;首先需要创建一个承诺,其次需要另一个 .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;
});
}
将 readFile()
从 fs.readFile()
的 general-purpose promisier 更改为 specialist 可以说是剥夺了代码的一些优雅,但肯定会提供更高的效率。此外,.map(readFileAndTakeAction)
的优雅不仅仅是补偿。
我最近 运行 在执行 node.js 文件时遇到问题。 我将 post 代码并解释问题所在。
我有 2 个文件,即 testit.js 和 test.js
在 test.js 中,我使用 module.exports
将包含文本文件文件路径的数组对象传递给 testit.js["a.txt","b.txt"]
在testit.js中,module.exports.text接受一个文件名数组对象,
通过 Object.keys(texts).forEach
、
处理每一个
通过 readFile
、
读取每个返回的缓冲区值
returns 通过 takeAction
该缓冲区中包含的文本
并将其存储在数组对象 newtexts
.
但是当新文本被解析并调用 returns 到 then() 时,其中新文本正在命令行上打印,它 returns 一个 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);
});
}
在解决整个 Promise 之前,您实际上需要等待所有 readFile Promise 解决。
替换
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 return 存储到一个数组中(或者更准确地说,我们存储一个 Promise,它在 readFile 完成后和结果处理后解析,并且存储到 newtexts 中),并且只有当数组中的所有 Promise 都已解决时,我们才会从这个函数中解决 return 的承诺。
值得避免不必要的承诺,因为它们是昂贵的操作。您可能想考虑以下问题:
- 外部
new Promise()
包装器是不必要的,因为您可以 return return 由Promise.all(promises)...
编辑的承诺。这不仅会摆脱不必要的承诺,还会将错误传播给调用者。请注意,在您自己的代码中,永远不会调用外部承诺的reject
。 - 从
takeAction()
返回一个新的承诺会降低两倍以上的效率;首先需要创建一个承诺,其次需要另一个 .then() (因此又是一个承诺)来访问结果。如果操作是同步的,尽量保持同步。 .then()
s 可以通过将buffer
的同步处理转移到readFile()
(适当重命名)来完全避免。同样,保持同步操作同步。
.map()
循环中的 试试这个:
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()
的 general-purpose promisier 更改为 specialist 可以说是剥夺了代码的一些优雅,但肯定会提供更高的效率。此外,.map(readFileAndTakeAction)
的优雅不仅仅是补偿。