蓝鸟地图早退

时间:2017-01-20 22:20:08

标签: javascript mongodb bluebird

我正在使用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);

有谁知道我可能做错了什么?

2 个答案:

答案 0 :(得分:3)

我在这里看到三个主要的错误:

  1. Bluebirds .map()需要一个返回promise的回调。
  2. 正在执行.then()的{​​{1}}句柄必须console.log(items),以便结果承诺仍然具有return items作为已解析的值。
  3. 当您致电items时,您必须使用returnInvoicePrice()来检索它的价值。该函数返回一个承诺,它是一个主承诺,可以监视.then()中的所有其他承诺。
  4. 传递给.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]);