我应该如何在节点 js 中使用 db + http 调用的承诺

How I should use promises for db + http calls in node js

我需要实施

的系统

我有使用类似回调的工作解决方案。

MongoClient.connect(dsn).then(function(db) {
    parentcollection.findOne({"_id" : new ObjectId(pid)}, function(err, data) {

    var redis = require("redis"),
    client = redis.createClient();

    client.on("error", function (err) {
        console.log("Error " + err);
    });

    // If not set

    client.get(cacheKey, function(err, data) {
        // data is null if the key doesn't exist
        if(err || data === null) {
            var options = {
                host: HOST,
                port: 80,
                path: URI
            };

            var req = http.get(options, function(res) {
                res.setEncoding('utf8');
                res.on('data', function (chunk) {
                    body += chunk;
                    //console.log('CHUNK: ' + chunk);
                });
                res.on('end', function () {
                    data = JSON.parse(body);


                    // Get childdata After process of data

                    childcollection.save(childdata, {w:1}, function(cerr, inserted) {
                        db.close();

                    });
                });
            }); 
        } else {
            // Get childdata from cache data
            childcollection.save(childdata, {w:1}, function(cerr, inserted) {
                db.close();
            });
        }
    });
});

我想使用 promise(原生的,而不是像 bluebird / request 这样的外部的)而不是回调。我查看手册并考虑是否需要那样实施

var promise1 = new Promise((resolve, reject) => {

    MongoClient.connect(dsn).then(function(db) {
        parentcollection.findOne({"_id" : new ObjectId(pid)}, function(err, data) {


    });

}}.then(function(data){
   var promise2 = new Promise((resolve, reject) => {
     var redis = require("redis"),
        client = redis.createClient();

        client.on("error", function (err) {
            console.log("Error " + err);
        });

        // If not set

        client.get(cacheKey, function(err, data) {
            // data is null if the key doesn't exist
            if(err || data === null) {
                var options = {
                    host: HOST,
                    port: 80,
                    path: URI
                };

                var promise3 = new Promise((resolve, reject) => {
                        var req = http.get(options, function(res) {
                            res.setEncoding('utf8');
                            res.on('data', function (chunk) {
                                body += chunk;
                                //console.log('CHUNK: ' + chunk);
                            });
                            res.on('end', function () {
                                data = JSON.parse(body);


                            // Get childdata After process of data


                        });
                    })
                }).then(function(data){
                    childcollection.save(childdata, {w:1}, function(cerr, inserted) {
                                db.close();

                            });
                });
            } else {
                // Get childdata from cache data
                childcollection.save(childdata, {w:1}, function(cerr, inserted) {
                    db.close();
                });
            }
        });

}}.then(function(data){
});
});              

哪个看起来像回调地狱一样肮脏,或者没有像上面那样使用 promises 的更好方法?

一个问题是您永远不会调用提供给 promise 构造函数回调的 resolve 函数。不调用它们,承诺永远不会解决。

我建议在单独的、可重用的函数中创建这些新承诺。另一方面,当您不提供回调参数时,一些 MongoDb 方法 return 已经承诺。

你可以像下面那样做。

// Two promisifying functions:
function promiseClientData(client, key) {
    return new Promise(function (resolve, reject) {
        return client.get(key, function (err, data) {
            return err ? reject(err) : resolve(data); // fulfull the promise
        });
    });
}

function promiseHttpData(options) {
    return new Promise(function (resolve, reject) {
        return http.get(options, function(res) {
            var body = ''; // You need to initialise this...
            res.setEncoding('utf8');
            res.on('data', function (chunk) {
                body += chunk;
                //console.log('CHUNK: ' + chunk);
            });
            res.on('end', function () {
                data = JSON.parse(body);
                resolve(data);  // fulfull the promise
            });
        );
    });
}

// Declare the db variable outside of the promise chain to avoid 
// having to pass it through
var db;

// The actual promise chain:
MongoClient.connect(dsn).then(function (dbArg) {
    db = dbArg;
    return parentcollection.findOne({"_id" : new ObjectId(pid)}); // returns a promise
}).then(function (data) {
    var redis = require("redis"),
    client = redis.createClient();
    client.on("error", function (err) {
        console.log("Error " + err);
    });
    // Get somehow cacheKey...
    // ...
    return promiseClientData(client, cacheKey);
}).then(function (data) {
    // If not set: data is null if the key doesn't exist
    // Throwing an error will trigger the next `catch` callback
    if(data === null) throw "key does not exist"; 
    return data;
}).catch(function (err) {
    var options = {
        host: HOST,
        port: 80,
        path: URI
    };
    return promiseHttpData(options);
}).then(function (data) {
    // Get childdata by processing data (in either case)
    // ....
    // ....
    return childcollection.save(childdata, {w:1}); // returns a promise
}).then(function () {
    db.close();
});

我假设 return 由 MongoDb 做出的承诺是完全合规的。有疑问的是,您可以通过对它们调用 Promise.resolve() 将它们变成原生 JavaScript promise,例如:

return Promise.resolve(parentcollection.findOne({"_id" : new ObjectId(pid)}));

或:

return Promise.resolve(childcollection.save(childdata, {w:1}));