在使用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它们。