2017-04-19 166 views
1

我需要实现系统我应该如何在使用DB + HTTP调用承诺节点JS

  • 从父集合中获取数据。
  • 检查在Redis的
  • 发现,如果没有那么做一个HTTP调用,并得到JSON数据然后设置缓存
  • 如果是,那么从缓存中
  • 将数据存入孩子收集父ID获取数据尤其关键。

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

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

我想使用承诺(本机,而不是外部的像蓝鸟/请求),而不是回调。我签手册和思考,如果我需要实现这样的

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

看起来像脏回调地狱或任何更好的办法,不使用的承诺像上面?

+0

因素了'新Promise'调用到额外的承诺,回国功能。 – Bergi

回答

1

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

我会建议在单独的,可重用的函数中创建这些新的承诺。另一方面,当你不提供回调参数时,一些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})); 
+0

感谢您的示例代码帮助我通过承诺编写代码,但是我不使用throw/catch作为redis的条件流,但使用类似于http://stackoverflow.com/a/33260670/1230744 –

+0

的功能流当然,这将工作。确保避免代码重复:'childcollection.save'应该只发生一次。此外,如果您不使用catch,请注意,如果发生异常,则链条被破坏,错误不会再被捕获。投掷/捕捉在承诺链中非常有效。 – trincot

+0

是的,我使用捕获承诺链中的所有通用失败,这是我犹豫是否使用catch作为正常事件的redis关键失败的主要原因。 –