【问题标题】:Correct way to cascate promises for arrays (mongoose example)为数组级联承诺的正确方法(猫鼬示例)
【发布时间】:2018-12-06 22:48:44
【问题描述】:

我需要了解使用 mongoose 级联 Promise 的正确方法。

我的函数 createCustomerBills 接收一个客户 ID 列表,我需要为每个客户创建一个简单的账单。

代码如下:

const createCustomerBill = (customer) => {
    return BillModel.create({
        customer_id: customer.id,
        value: 100
    });
}

const createCustomerBills => (customerIds) => {
    let criteria = {
        _id: { $in: customerIds }
    };

    return CustomerModel.find(criteria)
    .then(result => {
        return result.map(customer => {
            return createCustomerBill(customer);
        }
    })
    .then(result => {
        return CustomerModel.update(
                { _id: customer.id }, 
                { status: "BillCreated" }
        );
    });
}

步骤如下: 1.获取所有客户列表 2.为每个客户创建账单 3. 对于每张账单,更新客户状态

如果这是正确的方法和可能的缺点,我需要一个建议。

【问题讨论】:

  • createCustomerBill 完全是异步的吗?此外,您似乎只运行CustomerModel.update 一次,而不是每张账单一次
  • 是的,我需要全部异步,实际上我的理解是 createCustomerBill 是异步的(因为 mongoose create 是异步的)。我错了吗?
  • 那么你做错了,因为return result.map 立即返回一个数组,所以在调用CustomerModel.update 之前没有“等待”
  • Umm...所以看到更新状态代码需要是createCustomerBill: createCustomerBill(customer).then(...)then,在地图内,对吧? (这是我需要的那种建议……)

标签: javascript mongoose promise


【解决方案1】:

因为您正在映射 CustomerModel.find 的结果,所以返回该数组不会等待 promise 完成来运行下一个 .then,因为数组不是 Promise

这就是 Promise.all 的用武之地

此外,由于您需要单独更新每个账单,因此承诺链的这一部分需要在 .map 迭代中

const createCustomerBill = customer => 
    BillModel.create({
        customer_id: customer.id,
        value: 100
    });

const createCustomerBills => customerIds => {
    let criteria = {
        _id: { $in: customerIds }
    };

    return CustomerModel.find(criteria)
    .then(result => 
        Promise.all(
            result.map(customer => createCustomerBill(customer)
                .then(result => CustomerModel.update({ _id: customer.id }, { status: "BillCreated" }))
            )
        )
    )
    .then(result => {
        // all bills are now processed 
    });
}

【讨论】:

  • 为什么我需要Promise.all.. 只返回地图结果(return result.map(...).then(...) 不会是一个承诺数组?这两个返回有什么区别?
  • 你需要等待 所有 的承诺......如果调用 createCustomerBills 的代码需要等待进程完成,你只需要这个...... . 如果没有,那么你甚至不需要返回任何东西
  • 知道了!很好的答案。谢谢!
【解决方案2】:

这是一种可能的工作方式,IMO

const createCustomerBill = (customer) => {
  return BillModel.create({
    customer_id: customer.id,
    value: 100,
  });
}

const createCustomerBills => (customerIds) => {
  const criteria = {
    _id: {
      $in: customerIds,
    },
  };

  return CustomerModel.find(criteria)
    .then((customers) => Promise.all(customers.map(x => createCustomerBill(x)
      .then(() => CustomerModel.update({
        _id: x.id,
      }, {
        status: "BillCreated"
      })))))
    .then(() => console.log('over'))
    .catch(e => console.log(e));
}

这里使用了很棒的async/await

const createCustomerBill = customer => BillModel.create({
  customer_id: customer.id,
  value: 100,
});

const updateCustomer = customer => CustomerModel.update({
  _id: x.id,
}, {
  status: 'BillCreated',
});

const createBillAndUpdateCustomer = async(customer) => {
  await createCustomerBill(customer);
  
  await updateCustomer(customer);
};

const createCustomerBills => async(customerIds) => {
  const customers = await CustomerModel.find({
    _id: {
      $in: customerIds,
    },
  });

  await Promise.all(customers.map(x => createBillAndUpdateCustomer(x)));

  console.log('over');
}

【讨论】:

    猜你喜欢
    • 2015-05-12
    • 1970-01-01
    • 2015-11-19
    • 2018-09-01
    • 2012-12-14
    • 2017-06-15
    • 2019-06-04
    • 2017-08-18
    • 2018-02-15
    相关资源
    最近更新 更多