在使用Promise时挂在variables上的最佳做法
我对诺言是新的,我想知道什么最好的做法是保持variables,而下链?
通过Promise连接到MongoDB非常简单:
connectToMongoDB(data).done(function(db) { var collection = db.collection('test_inserts'); // do more stuff here });
但是如果我必须连接到两个不同的数据库会发生什么?
connectToMongoDB1(data1).then(function(db1) { return connectToMongoDB2(data2); }).done(function(db2) { var collection = db1.collection('test_inserts'); // ERROR: db1 is undefined });
那个错误非常有意义。 但是,如何转发db1
而不改变我的connectToMongoDB2()
函数,因为我想保持connectToMongoDB2()
和所有我的承诺一般非常通用?
我的意思是,我可以围绕一个对象存储所有相关的东西,但是这看起来有点怪异:
var relevantStuff = {}; connectToMongoDB1(data1).then(function(db1) { relevantStuff.db1 = db1; return connectToMongoDB2(data2); }).done(function(db2) { var collection = relevantStuff.db1.collection('test_inserts'); // do more stuff here });
最佳做法是什么?
注意:我在这个答案中使用蓝鸟 。
有三种方法可以做你想做的事情:closures,绑定和Promise.using
。
封闭是@Sukima展示的方式。
function promisedFunc() { var db; return getCollection().then(function(col) { db = col; return db.query(stuff); }).then(function() { return db.query(otherStuff); }); }
绑定 :使用Promise.bind
,你可以使this
对象保存值。
function promisedFunc() { return getCollection().bind({}).then(function(col) { this.db = col; return this.db.query(stuff); }).then(function() { return this.db.query(otherStuff); }); }
最后 ,bluebird v2引入的最后一种方式是使用真实资源pipe理。
function promisedFunc() { return Promise.using(getDb(), function(db) { return db.query(stuff).then(function() { return db.query(otherStuff); }); }); }
我将进一步解释getDb
方法。
最后一种方式提供了另一个非常有趣的好处:处理资源。 例如,您经常需要调用数据库资源的close
方法。 Promise.using
让你创buildPromise.using
,运行一旦它的承诺解决(或不)。
要明白为什么这是一个优势,让我们来回顾一下这3个方法。
closures:
var db, close; return getCollection().spread(function(col, done) { db = col; close = done; return db.query(stuff); }).then(function() { return db.query(otherStuff); }).finally(function() { close(); });
是的,这意味着每次使用db连接时都必须编写所有的样板文件 。 别无select。
现在让我们看看绑定方式:
return getCollection().bind({}).spread(function(col, done) { this.db = col; this.close = done; return this.db.query(stuff); }).then(function() { return this.db.query(otherStuff); }).finally(function() { this.close(); });
但是,现在可以模块化了。
var db = { getDb: function() { return getCollection().bind({}); }, close: function() { this.close(); } }; return db.getDb().then(function() { return this.db.query(stuff); }).then(function() { return this.db.query(otherStuff); }).finally(db.close);
这已经好多了! 但是我们还是要考虑finally
使用。
然后,蓝鸟, Promise.using
引入的方式。 通过这样声明:
function getDb() { var close; return getCollection().spread(function(db, done) { close = done; return db; }).disposer(function() { close(); }); }
你可以简单地使用它,如前所见:
return Promise.using(getDb(), function(db) { return db.query(stuff).then(function() { return db.query(otherStuff); }); });
finally
不用考虑,也没有样板。
通常如果你pipe理多个返回值(在你的情况),它是以某种forms封装的。 以下是一些受欢迎的选项:
- 外部作用域variables
- 在每个链式函数中返回多个值的数组
- 或使用一个对象来表示各种状态,并用每个链接的函数返回该对象的实例。
外部范围variables:
function promisedFunc() { var db; return getCollection() .then(function(db1) { db = db1; // Do stuff return stuff; }) .then(function(db1) { // Do stuff return db.stuff; }); }
返回多个值:
function getConnection() { return getCollection() .then(function(db1) { // Do stuff return [stuff, db1]; }) .then(function(args) { var stuff = args[0]; var db = args[1]; // Do stuff return [db.moreStuff, db]; }); }
对象:
function getConnection() { function DB(db1, stuff) { if (db1 instanceof DB) { return new DB(db1.db1, stuff); } this.db1 = db1; this.stuff = stuff; } // Add to prototype etc. return getCollection() .then(function(db1) { // Do stuff return new DB(db1, stuff); }) .then(function(db) { // Do stuff return new DB(db, stuff); }); }
这是我需要做的,在需要范围访问的通用情况下。 我会用承诺作为代理。 其他答案忽略了我个人经常使用的这种技术,我认为这是一个值得考虑的select。
假设蓝鸟:
var db1 = connectToMongoDB(data1); var db2 = connectToMongoDB(data2); // if needs sequencing, do db1.then... Promise.join(db1,db2,function(db1,db2){ // access both connections here, here both promises are available // in native promises this is Promise.all([db1,db2]).then(...) });
如果您实际需要等待DB1并且无法并行连接,则不需要等待所有嵌套,所有内容都是串行的:
var db1 = connectToMongoDB(data1); var db2 = db1.then(function(data){ data2 = data[0]; connectToMongoDB(data2);});
至于资源pipe理 – 请查看Florian的好答案 – 尽pipe在这种情况下,MongoDB连接是build立在持久性的基础上的,您应该在应用程序中正确地打开/closures它们。