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

时间:2016-12-23 18:06:18

标签: javascript node.js promise arrayobject

我最近在执行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);
    });
}

3 个答案:

答案 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)的优雅不仅仅是补偿。