node.js〜构造Promise链式序列parsing

任何人都可以build议一个更好的方式来构build这种使用承诺? 我对Promises很陌生,在想如果我错过了一些关于如何构build这个事件链的东西。

注意:这是我的意图,不要在这里使用rej [ect]。 你看到guatanrees只有res [olve]返回。 这意味着返回的代码只需要一个path来处理返回的值。 由此返回的代码在stream程中更简单。

这可能有助于了解,如果你不认识它,这是从我创build的模块。 把它想成一个道。

module.exports = { dbConnection: function () { return { user: 'sa', password: 'mypassword', server: 'localhost', database: 'mydb' }; }, CanIConnectToTheDB: function () { return new Promise(function (res, rej) { var sql = require('mssql'); var myDao = require('./myDao'); var cn = new sql.ConnectionPool(myDao.dbConnection()); cn.connect().then(function () { var req = new sql.Request(cn); var qry = 'select serverproperty(\'productversion\') as \'rs\''; req.query(qry) .then(function (rs) { qry = 'select isnull(object_id(\'SomeObjectIKnowExists\'), -1)'; req.query(qry) .then(function (rss) { res(' CONNECTED// MASTER DB SUCCESS// MY DB SUCCESS'); }) .catch(function (err) { res(' CONNECTED// MASTER DB SUCCESS// ISSUE QUERYING MY DB //' + err + '//'); }); }) .catch(function (er) { res(' CONNECTED// COULD NOT QUERY MASTER DB //' + er + '//'); }); }) .catch(function () { res(' CAN NOT CONNECT'); }); }); } }; 

关于承诺要记住的关键是, then 返回一个新的承诺 (如catch )。 新的承诺如何解决取决于你从处理程序返回的内容:如果你返回一个承诺,那么来自/ catch的新的承诺then被归于你所返回的承诺。 如果您返回一个值,则新的承诺将以该值解决。

所以你可以把它们连在一起 想想thencatch处理程序作为转换filter的最终结果stream通过。

还要注意的是,如果你有一个起点( cn.connect() ),你不需要new Promise :只需使用thencatch来通过返回(新)parsing值。

另一个要记住的关键是,如果一个catch处理程序返回一个值,它将拒绝转换为一个parsing。 要继续拒绝path, catch处理程序必须抛出一个exception或返回一个将被拒绝的promise。

最后: require调用应始终在模块的开始处。

所以,如果不删除你的拒绝决议的转换(更多的在一瞬间):

 var sql = require('mssql'); var myDao = require('./myDao'); module.exports = { dbConnection: function () { return { user: 'sa', password: 'mypassword', server: 'localhost', database: 'mydb' }; }, CanIConnectToTheDB: function () { var cn = new sql.ConnectionPool(myDao.dbConnection()); return cn.connect() .then(function () { var req = new sql.Request(cn); var qry = 'select serverproperty(\'productversion\') as \'rs\''; return req.query(qry) .then(function (rs) { qry = 'select isnull(object_id(\'SomeObjectIKnowExists\'), -1)'; return req.query(qry) .then(function (rss) { // Note you're not using rss anywhere return ' CONNECTED// MASTER DB SUCCESS// MY DB SUCCESS'; }) .catch(function (err) { return ' CONNECTED// MASTER DB SUCCESS// ISSUE QUERYING MY DB //' + err + '//'; }); }) .catch(function (er) { return ' CONNECTED// COULD NOT QUERY MASTER DB //' + er + '//'; }); }) .catch(function() { return ' CAN NOT CONNECT'; }); } }; 

注意:这是我的意图,不要在这里使用rej [ect]。 你看到guatanrees只有res [olve]返回。 这意味着返回的代码只需要一条path来处理返回的值。 由此返回的代码在stream程中更简单。

出于某种原因,拒绝遵循分辨率的不同path。 它不会使事情变得更复杂,它使事情变得更简单 。 不要将拒绝转换为解决scheme,除非您完成了某种错误恢复,并可继续进行,犹如拒绝没有发生。

这里是拒绝被拒绝的代码:

 var sql = require('mssql'); var myDao = require('./myDao'); module.exports = { dbConnection: function () { return { user: 'sa', password: 'mypassword', server: 'localhost', database: 'mydb' }; }, CanIConnectToTheDB: function () { var cn = new sql.ConnectionPool(myDao.dbConnection()); return cn.connect() .then(function () { var req = new sql.Request(cn); var qry = 'select serverproperty(\'productversion\') as \'rs\''; return req.query(qry) .then(function (rs) { qry = 'select isnull(object_id(\'SomeObjectIKnowExists\'), -1)'; return req.query(qry) .then(function (rss) { // Note you're not using rss anywhere return ' CONNECTED// MASTER DB SUCCESS// MY DB SUCCESS'; }); }); }); } }; 

使用它:

 theModule.CanIConnectToTheDB() .then(function() { // Yes, let's do something }) .catch(function() { // No, report the problem, etc. }); 

我也可能抽象出我假设你最终会反复做的一点:build立一个连接并从中获取一个请求对象:

 var sql = require('mssql'); var myDao = require('./myDao'); function getRequest() { var cn = new sql.ConnectionPool(myDao.dbConnection()); return cn.connect().then(function() { return new sql.Request(cn); }); } module.exports = { dbConnection: function () { return { user: 'sa', password: 'mypassword', server: 'localhost', database: 'mydb' }; }, CanIConnectToTheDB: function () { return getRequest().then(function(req) { var qry = 'select serverproperty(\'productversion\') as \'rs\''; return req.query(qry) .then(function (rs) { qry = 'select isnull(object_id(\'SomeObjectIKnowExists\'), -1)'; return req.query(qry) .then(function (rss) { // Note you're not using rss anywhere return ' CONNECTED// MASTER DB SUCCESS// MY DB SUCCESS'; }); }); }); } }; 

而不是像这样的东西:

  .then(function (rs) { qry = '...'; req.query(qry) .then(function (rss) { 

你可以使用这样的东西:

  .then(function (rs) { qry = '...'; return req.query(qry); }).then(function (rss) { 

也就是说,您可以在一个callback中返回一个承诺,并在下一个callback中获得该承诺的parsing值,所以您的缩进保持不变。

更简单的例子 – 而不是这个:

 a().then(va => { b(va).then(vb => { c(vb).then(vc => { // you can use vc here }); }); }); 

你可以做:

 a().then(va => { return b(va); }).then(vb => { return c(vb); }).then(vc => { // you can use vc here }); 

或者,如果您使用asyncawait async简单:

 va = await a(); vb = await b(va); vc = await c(vb); // you can use vc here 

请注意,您只能在使用async关键字创build的函数内部使用await 。 在你没有本地支持asyncawait你可以使用Babel或稍微不同的语法,像co或Bluebird协程中的基于生成器的方法。 有关浏览器和节点的更多信息和支持,请参阅此答案:

  • 有没有更好的方式与Node.js运行CLI命令?

更新

这没有经过testing,但这或多或less是我会写的:

 module.exports = { dbConnection: function () { return { user: 'sa', password: 'mypassword', server: 'localhost', database: 'mydb' }; }, CanIConnectToTheDB: function () { var sql = require('mssql'); var myDao = require('./myDao'); var cn = new sql.ConnectionPool(myDao.dbConnection()); var req; return cn.connect() .catch(err => Promise.reject('Error 1: ' + err)) .then(() => { req = new sql.Request(cn); var qry = 'select serverproperty(\'productversion\') as \'rs\''; return req.query(qry) .catch(err => Promise.reject('Error 2: ' + err)); }).then(rs => { var qry = 'select isnull(object_id(\'SomeObjectIKnowExists\'), -1)'; return req.query(qry) .catch(err => Promise.reject('Error 3: ' + err)); }).then(function (rss) { return 'CONNECTED// MASTER DB SUCCESS// MY DB SUCCESS'; }).catch(err => { // if you want it always resolved: return 'CAN NOT CONNECT: ' + err; }); } }; 

当然我会保留这个函数返回的最后的承诺在错误上被拒绝并且只在成功时才被解决,但是因为你在你的问题中明确地包含了这个奇怪的要求,所以我把它写成了你想要的。

但是,如果它拒绝任何错误的承诺,那么它会更容易使用,特别是如果你所关心的是在function名称的问题的答案 – 我可以连接到DB:

 CanIConnectToTheDB() .then(() => console.log("Yes I can")) .catch(() => console.log("No I can't")); 

更多信息:

有关更多信息,请参阅以下答案

  • 如何将瀑布法转换为承诺
  • jQuery:Ajax调用成功后返回数据 (请参阅此答案更新中的解释)