2013-10-17 16 views
17

Attualmente sto imparando come utilizzare le promesse in nodejspromesse con FS e Bluebird

così la mia prima sfida era quello di elencare i file in una directory e quindi ottenere il contenuto di ogni con entrambe le fasi utilizzando le funzioni asincrone. Sono venuto con la seguente soluzione, ma hanno una forte sensazione che questo non è il modo più elegante per fare questo, soprattutto la prima parte dove sto "girando" i metodi asincroni in promesse

// 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 
} 

Ora concatenare sia promette:

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) 
}) 

Come ho scritto sopra, restituisce il risultato desiderato, ma sono abbastanza sicuro che c'è un modo più elegante per questo.

risposta

43

Il codice può essere reso più breve utilizzando generic promisification e il metodo .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) 
}); 

In realtà si potrebbe tagliare questo ancora di più dal momento che le funzioni non stanno tirando più il loro peso:

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 dovrebbe essere il tuo metodo pane e burro quando si lavora con le collezioni - è davvero potente in quanto funziona per qualsiasi cosa, da una promessa per una serie di promesse che mappano a ulteriori promesse a qualsiasi combinazione di valore diretto nel mezzo.

+2

Nice, anche per indicare ai futuri lettori di utilizzare le funzioni 'Async':' readdirAsync', 'readFileAsync'. – Wtower