有人能建议一种更好的方法来构建Promises的使用吗? 我对Promises很新,我想知道我是否错过了如何构建这一系列事件的方法。
注意:我打算不在这里使用rej [ect]。 你看到guatanrees只有res [olve]返回。这意味着返回的代码只需要一个路径来处理返回的值。 因此,返回的代码在其流程中更为简单。
如果你不认识它,可能会有所帮助,这是从我创建的模块中获取的。把它想象成道。
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');
});
});
}
};
答案 0 :(得分:5)
而不是像这样:
.then(function (rs) {
qry = '...';
req.query(qry)
.then(function (rss) {
你可以使用这样的东西:
.then(function (rs) {
qry = '...';
return req.query(qry);
}).then(function (rss) {
即。您可以在一个then
回调中返回一个承诺,并在下一个then
回调中获得该承诺的已解析值,这样您的缩进就会保持不变。
更简单的例子 - 而不是:
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
});
或者,如果您使用async
和await
,则更简单:
va = await a();
vb = await b(va);
vc = await c(vb);
// you can use vc here
请注意,您只能在使用await
关键字创建的函数中使用async
。在您不具备async
和await
原生支持的地方,您可以使用Babel或稍微不同的语法,基于生成器的方法,如co
或Bluebird协同程序。有关浏览器和节点的更多信息和支持,请参阅以下答案:
这未经过测试,但这或多或少都是我写的:
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;
});
}
};
当然,我会保留该函数返回的最终承诺在错误时被拒绝,并且仅在成功时解决,但由于您在问题中明确包含了这个奇怪的要求,所以我按照您的意愿编写了它。
但是如果它拒绝了对任何错误的承诺那么它会更容易使用,特别是如果你关心的只是函数名称中问题的答案 - 我可以连接到数据库:
CanIConnectToTheDB()
.then(() => console.log("Yes I can"))
.catch(() => console.log("No I can't"));
有关详情,请参阅以下答案:
答案 1 :(得分:4)
要记住关于promises的关键是then
返回一个新的承诺(和catch
一样)。如何解决新的承诺取决于您从处理程序返回的内容:如果您返回一个承诺,then
/ catch
的新承诺将从属于您返回的承诺;如果返回值,则使用该值解析新的promise。
所以你可以将它们连在一起。将then
和catch
处理程序视为转换最终结果流过的过滤器。
另请注意,如果您的起点可以为您提供承诺(cn.connect()
),则您不需要new Promise
:只需使用then
和{{1}通过返回(新)分辨率值来转换通过链的内容。
要记住的另一个关键事项是,如果catch
处理程序返回一个值,它会将拒绝转换为分辨率。要继续拒绝拒绝路径,catch
处理程序必须抛出异常或返回将被拒绝的承诺。
最后:catch
调用应始终位于模块的开头。
因此,在不删除拒绝转换为解决方案的情况下(稍后会详细介绍):
require
注意:我打算不在这里使用rej [ect]。你看到guatanrees只有res [olve]返回。这意味着返回的代码只需要一个路径来处理返回的值。因此,返回的代码在其流程中更为简单。
出于某种原因,拒绝遵循决议的单独路径。它不会使事情变得更复杂,它会使事情更简单。不要将拒绝转换为决议,除非你做了某种错误恢复,并且可以继续,好像拒绝没有发生。
这里的代码允许拒绝拒绝:
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';
});
}
};
使用它:
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.
});