我正在使用Bluebird.map
,但由于某种原因,它会提前返回我的对象数组:
function returnInvoicePrice(items) {
return Bluebird.map(items, function(item) {
db.collection('products').find({
product_code : item.product_code
}).toArray(function(err, product) {
var invoice_price = product[0].invoice_price;
console.log('--product--');
console.log(product);
return product;
});
}).then(function(items) {
console.log('--items w/ invoice price--'); // this prints BEFORE my console.log(product) for some reason...
console.log(items);
}).catch(function(error) {
console.log('--bluebird error in returning price for each item--');
console.log(error);
});
}
returnInvoicePrice(items);
有谁知道我可能做错了什么?
答案 0 :(得分:3)
我在这里看到三个主要的错误:
.map()
需要一个返回promise的回调。.then()
的{{1}}句柄必须console.log(items)
,以便结果承诺仍然具有return items
作为已解析的值。items
时,您必须使用returnInvoicePrice()
来检索它的价值。该函数返回一个承诺,它是一个主承诺,可以监视.then()
中的所有其他承诺。 传递给.map()
的函数需要返回在异步操作完成时解析的承诺。如果它没有返回任何内容或返回一个普通值,那么Bluebird不能等到异步操作完成,因此会比你想要的更早返回。
如果你的版本还不支持promises,那么有mongodb-promise之类的软件包会为你提供mongodb的promise接口,或者你可以使用Bluebird的Bluebird.map()
或{{ 1}}在mongodb中宣传接口。
最新版本的mongodb for node支持所有异步接口中的promise,因此您可以直接返回它提供的promise。
从this doc for the latest mongodb看来.promisify()
会返回一个承诺,因此您可以直接从这样的.promisifyAll()
回调中返回该承诺(并修复其他错误):
xxx.find().toArray()
答案 1 :(得分:0)
如果您运行此代码:
var Bluebird = require('bluebird');
function returnInvoicePrice(items) {
return Bluebird.map(items, function(item) {
console.log(item);
return item;
}).then(function(items) {
console.log('--items w/ invoice price--'); // this prints BEFORE my console.log(product) for some reason...
console.log(items);
}).catch(function(error) {
console.log('--bluebird error in returning price for each item--');
console.log(error);
});
}
returnInvoicePrice([1,2,3]);
您将看到您期望的订单。区别在于,正如jfriend00所暗示的那样,db.collection.find(...)是异步的,在将来的某个时刻执行。因此,您需要将该部分包装在Promise中:
return new Promise(function (resolve, reject) {
db.collection.find({
:
resolve(); // this will signal Bluebird to execute the mapper function
});
}
这样,Bluebird知道在继续之前等待响应。
您可以通过运行模拟异步过程的代码来看到这一点:
var Bluebird = require('bluebird');
function returnInvoicePrice(items) {
return Bluebird.map(items, function(item) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(item);
resolve(item);
}, 500);
});
}).then(function(items) {
console.log('--items w/ invoice price--'); // this prints BEFORE my console.log(product) for some reason...
console.log(items);
}).catch(function(error) {
console.log('--bluebird error in returning price for each item--');
console.log(error);
});
}
returnInvoicePrice([1,2,3]);