2016-12-23 102 views
1

我最近在执行node.js文件时遇到了问题。 我会发布代码并解释问题所在。Promise为什么返回(解析)Node.js中的空对象?

我有2个文件即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解决并调用返回到然后(),其中newtexts被印刷在命令行,则返回空的Array对象而不是返回的每个这些文件的文件内容的阵列对象。

有人可以解释我在代码中出错的地方吗? 感谢提前一吨。

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

因为在实际添加到新文本之前,您正在调用resolve(newtexts)。 forEach()回调甚至没有开始执行,直到到达决定行。使用'array.map'将你的文本数组映射到一个Promises数组,然后使用'Promise.all()。then()'等到数组中的每个Promise完成后再解析Promise。 – PMV

+0

我是Node.js的新手,所以如果可能的话,你可以请一个解决方案吗? –

+0

不是答案,但我觉得很奇怪你在一个数组上使用Object.keys并访问array [key]。为什么不只是遍历数组呢? – Gerrit0

回答

1

实际上你需要等待所有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的每个呼叫到一个数组(或者更准确地说,我们存储在readFile完成后以及在结果被处理并存储到newtexts之后解析的Promise),并且只有当数组中的所有Promise都已解决时,我们才能解决从此函数返回的许诺。

0

@pmv现在你提到了Promise.all和.map,现在所有的东西都有意义。在此更好地了解我remodified代码在takeAction返回一个Promise

var takeAction = function (text) { 
    return new Promise(function (resolve,reject){ 
     resolve(text.toString()); 
    }); 
} 

而且里面textPromises readFile回到刚经过:

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

非常感谢你的帮助:)

0

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

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

改变从fs.readFile()通用promisifier readFile()成专家可以说是剥夺了一些优雅的代码,但肯定提供了更高的效率。此外,.map(readFileAndTakeAction)的优雅多于补偿。

相关问题