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

我需要执行哪个系统

  • 从父集合获取数据。
  • 检查在redis中find的特定密钥
  • 如果没有,然后做一个http调用并获取json数据,然后设置caching
  • 如果是,则从caching中获取数据
  • 将数据保存到父标识的子集合中。

我有使用callback这样的工作解决scheme。

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

我想使用诺言(本机,而不是外部的像蓝鸟/请求),而不是callback。 我结帐手册,并思考如果我需要这样的实施

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

看起来像callback地狱一样肮脏或任何更好的方法,不使用上面的承诺?

一个问题是,你永远不会调用提供给promise构造函数callback的parsing函数。 没有给他们打电话,承诺永远不会解决。

我会build议在单独的,可重用的函数中创build这些新的承诺。 另一方面,当你不提供callback参数时,一些MongoDb方法已经返回了promise。

你可以像下面这样做。

 // 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(); }); 

我认为MongoDb返回的承诺是完全合规的。 有疑问的是,你可以通过在它们上调用Promise.resolve()来把它们变成原生的JavaScript承诺,比如像这样:

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

要么:

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