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
Simon H 16 Aug. 2015 im 22:18

3 Antworten

Beste Antwort

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?

0
Community 23 Mai 2017 im 10:33

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.
0
jib 18 Aug. 2015 im 12:06

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),
    ]);
});
1
Ry- 16 Aug. 2015 im 19:25