2013-10-17 146 views
17

目前,我正在学习如何在承诺与FS和蓝鸟

的NodeJS

使用的承诺,所以我的第一个挑战是列出目录中的文件,然后让每个使用异步函数两个步骤的内容。我想出了以下解决方案,但有一个强烈的感觉,这是不是最优雅的方式来做到这一点,尤其是第一部分,我在哪里“转向”异步方法分为承诺

// purpose is to get the contents of all files in a directory 
// using the asynchronous methods fs.readdir() and fs.readFile() 
// and chaining them via Promises using the bluebird promise library [1] 
// [1] https://github.com/petkaantonov/bluebird 

var Promise = require("bluebird"); 
var fs = require("fs"); 
var directory = "templates" 

// turn fs.readdir() into a Promise 
var getFiles = function(name) { 
    var promise = Promise.pending(); 

    fs.readdir(directory, function(err, list) { 
     promise.fulfill(list) 
    }) 

    return promise.promise; 
} 

// turn fs.readFile() into a Promise 
var getContents = function(filename) { 
    var promise = Promise.pending(); 

    fs.readFile(directory + "/" + filename, "utf8", function(err, content) { 
     promise.fulfill(content) 
    }) 

    return promise.promise 
} 

现在链中承诺:

getFiles() // returns Promise for directory listing 
.then(function(list) { 
    console.log("We got " + list) 
    console.log("Now reading those files\n") 

    // took me a while until i figured this out: 
    var listOfPromises = list.map(getContents) 
    return Promise.all(listOfPromises) 

}) 
.then(function(content) { 
    console.log("so this is what we got: ", content) 
}) 

正如我上面写的,它返回所需的结果,但我敢肯定有一个更优雅的方式来做到这一点。

回答

43

的代码可以通过使用generic promisification.map方法来缩短:

var Promise = require("bluebird"); 
var fs = Promise.promisifyAll(require("fs")); //This is most convenient way if it works for you 
var directory = "templates"; 

var getFiles = function() { 
    return fs.readdirAsync(directory); 
}; 
var getContent = function (filename) { 
    return fs.readFileAsync(directory + "/" + filename, "utf8"); 
}; 

getFiles().map(function (filename) { 
    return getContent(filename); 
}).then(function (content) { 
    console.log("so this is what we got: ", content) 
}); 

事实上,你可能因为功能的进一步修整此不再被拉着自己的体重:

var Promise = require("bluebird"); 
var fs = Promise.promisifyAll(require("fs")); //This is most convenient way if it works for you 
var directory = "templates"; 

fs.readdirAsync(directory).map(function (filename) { 
    return fs.readFileAsync(directory + "/" + filename, "utf8"); 
}).then(function (content) { 
    console.log("so this is what we got: ", content) 
}); 

.map在处理集合时应该是你的面包和黄油方法 - 它的功能非常强大,因为它适用于承诺数组的任何承诺,这些承诺映射到对任何直接值组合的进一步承诺中间。

+2

不错,同时指出以后的读者可以使用'Async'函数:'readdirAsync','readFileAsync'。 – Wtower