Ich bin auf Promise Anti-Patterns aufmerksam geworden und befürchte, dass ich mich hier auf eines verliebt habe (siehe Code-Auszug aus einer Funktion heraus). Wie zu sehen ist, habe ich Versprechen in zwei asynchronen Knotenfunktionen verschachtelt. Die einzige Möglichkeit, das innere Versprechen aufzudecken, ist die Verwendung eines äußeren. Ich würde eine Anleitung begrüßen, wie man dies eleganter schreibt.
function xyz() {
return new Promise(function(resolve, reject) {
return Resto.find({recommendation: {$gte: 0}}, function (err, data) {
if (err) return reject("makeSitemap: Error reading database");
return fs.readFile(__dirname + '/../../views/sitemap.jade', function(err, file) {
if (err) return reject("makeSitemap: Error reading sitemap template");
[snip]
resolve(Promise.all([
NLPromise('../m/sitemap.xml', map1),
NLPromise('../m/sitemap2.xml', map2)
]));
});
});
});
}
Ich habe das Problem auch in diesem plnkr festgestellt
3 Antworten
Auf Vorschlag von minitech schrieb ich:
readFileAsync = function(fname) {
return new Promise(function(resolve, reject) {
fs.readFile(fname, function (err, data) {
if (err) return reject(err);
resolve(data);
})
});
};
Und dann, unter Verwendung von Robertkleps Beobachtung, dass Mungo ein Versprechen zurückgeben kann, endete ich mit:
var datasets; // seemingly unavoidable semi-global variable with simple Promises
return Resto.find({recommendation: {$gte: 0}})
.then(function(data) {
datasets = _.partition(data, function(r) {
return _.includes([0,1], r.recommendation);
});
return readFileAsync(__dirname + '/../../views/sitemap.jade');
})
.then(function(file) {
[snip]
return Promise.all([
NLPromise('../m/sitemap.xml', map1),
NLPromise('../m/sitemap2.xml', map2)
]);
});
Ich kann weiterhin mit an der globalen Variablen arbeiten Wie greife ich auf frühere Versprechungsergebnisse in einer .then () -Kette zu?
Da dies mit es6-promise
markiert ist, wollte ich eine es6-Antwort hinterlassen, die keine Erweiterungen verwendet:
var xyz = () => new Promise((r, e) => Resto.find({recommendation: {$gte: 0}},
err => err ? e(err) : r()))
.then(() => new Promise((r, e) =>
fs.readFile(__dirname + '/../../views/sitemap.jade',
err => err? e(err) : r())))
// [snip]
.then(() => Promise.all([
NLPromise('../m/sitemap.xml', map1),
NLPromise('../m/sitemap2.xml', map2)
]));
Anti-Muster zu vermeiden:
- Nisten. Ketten nach Möglichkeit abflachen. Verwenden Sie
new Promise
eng. - Fehler ausblenden. Teilen Sie die wahre Fehlerursache nach Möglichkeit mit.
- Fäden werfen. Wirf echte Fehlerobjekte, da sie Stapelspuren haben.
Die beste Lösung besteht darin, vielversprechende Versionen von Rückruffunktionen zu erstellen. bluebird, eine hervorragende Versprechen-Implementierung (besser als die native von Node), verfügt über diese integrierte Funktion.
Bluebird.promisifyAll(Resto); // If you can promisify the prototype, that’s better
Bluebird.promisifyAll(fs);
function xyz() {
return Resto.findAsync({recommendation: {$gte: 0}}).then(function (data) {
return fs.readFileAsync(__dirname + '/../../views/sitemap.jade').then(function (file) {
…
return Bluebird.all([
NLPromise('../m/sitemap.xml', map1),
NLPromise('../m/sitemap2.xml', map2)
]);
});
});
}
Wenn das fs.readFile
nicht vom Resto.findAsync
abhängt, sollten Sie sie wahrscheinlich zusammen ausführen:
return Bluebird.all([
Resto.findAsync({recommendation: {$gte: 0}}),
fs.readFileAsync(__dirname + '/../../views/sitemap.jade'),
]).spread(function (data, file) {
…
return Bluebird.all([
NLPromise('../m/sitemap.xml', map1),
NLPromise('../m/sitemap2.xml', map2),
]);
});