0

我目前正在尝试返回一个 JSON 对象数组,该数组需要我执行一个异步函数,然后执行四个嵌套的异步映射函数以填充实体数组。基本上,每个用户都有一个订单数组,每个订单都有一个项目数组,每个项目都有一个选项数组,每个选项都有一个值数组。我正在使用 loopback4 框架,因此一旦填充了所有内容,就无法执行 res.send。该函数似乎在第一次等待时返回,但之后的任何等待,它都不会等待它,而是运行到函数的末尾。我曾尝试使用 Promises 和 .thens(),但似乎无法弄清楚如何填充完全嵌套的每个实体,然后返回填充的实体数组。我不断得到一个空数组。下面只有一窝地图,但我什至无法让它填充到第一个巢穴并返回它,所以我决定不再继续。这是代码:

async getUserOrders2(@param.path.number('id') id: number): Promise<any> {
      if ( !this.user) {
        throw new HttpErrors.Unauthorized(AuthErrorKeys.ClientInvalid);
      }
      else if (this.user.id != id) {
        throw new HttpErrors.Unauthorized(AuthErrorKeys.ClientInvalid);
      }
      else  {
        let restaurantId = this.user.restaurantId
        let orderFrameArray = new Array<OrderFrame>()
        return this.restaurantRepository.orders(restaurantId as string).find()
        .then(async orders => {
          orders.map(async (val, key)=> {
            let orderFrame = new OrderFrame(val)
            orderFrame.itemArray = await this.orderRepository.orderItems(val.id).find()
            orderFrameArray.push(orderFrame)
          })
          orderFrameArray = await Promise.all(orderFrameArray)
          return orderFrameArray
        })
      }
}

该函数在 orderFrameArray 被填充之前返回。我需要四个嵌套的地图循环,而第一个不工作,所以我不知道如何做剩下的。任何帮助将不胜感激。

基于@Tomalaks 解决方案,我尝试了以下方法,但它仍然只返回顶级数组并且没有嵌套:

    async getUserOrders2(@param.path.number('id') id: number): Promise<any> {
      if ( !this.user) {
        throw new HttpErrors.Unauthorized(AuthErrorKeys.ClientInvalid);
      }
      else if (this.user.id != id) {
        throw new HttpErrors.Unauthorized(AuthErrorKeys.ClientInvalid);
      }
      else  {
        let restaurantId = this.user.restaurantId
        let orderFrameArray = new Array<OrderFrame>()
        return this.restaurantRepository.orders(restaurantId as string).find()
          .then(orders => {Promise.all(orders.map(
          order => { 
          let orderFrame = new OrderFrame(order)
          orderFrame.itemArray = new Array<Item>()
          this.orderRepository.orderItems(order.id).find()
            .then(orderItems => Promise.all(orderItems.map(
            orderItem => {
            let itemFrame = new Item(orderItem)
            itemFrame.options = new Array<Option>()
            this.orderItemRepository.orderItemOptions(orderItem.id).find()
                .then(orderItemOptions => Promise.all(orderItemOptions.map(
                orderItemOption => { 
                let optionFrame = new Option(orderItemOption)
                optionFrame.values = new Array<Value>()
                this.orderItemOptionRepository.orderItemOptionValues(orderItemOption.id).find()
                    .then(orderItemOptionValues => Promise.all(orderItemOptionValues.map(
                    orderItemOptionValue => { 
                    let valueFrame = new Value(orderItemOptionValue)
                    optionFrame.values.push(valueFrame)})))
                itemFrame.options.push(optionFrame)})))
              orderFrame.itemArray.push(itemFrame)})))
            orderFrameArray.push(orderFrame)}))
          return orderFrameArray})
      }
    }

我为格式化道歉,我不确定如何最好地格式化它。还有什么我做错了吗?

感谢大家的回复。@Tomalak 发布的答案是正确的。我只需要将整个函数括在括号中,然后放一个 .then 来返回我制作的填充实体

4

1 回答 1

3

只有在同一个函数中async使用时才需要使用。await如果await嵌套函数中有,则父函数不需要async.

但是,在您的情况下,首先不应该创建任何功能async

  • 等待函数中的任何结果没有任何好处,因为内部没有任何代码依赖于任何中间结果。只需在得到承诺时返回承诺即可。
  • 不需要中间结果变量,例如orderFrameArray,您通过等待单个订单并将它们推送到顶级变量的方法使事情变得更难。
  • await像在调用中那样在循环中使用.map()对性能不利。您基本上是以这种方式序列化数据库访问——下一个查询只会在当前查询返回后发送。这种菊花链使数据库无法处理多个并发请求。
  • getUserOrders2不是Promise<any>,是Promise<Array<OrderFrame>>
  • throw无论如何都会终止函数,您可以在不使用else if. 这减少了嵌套。

所以一个完全异步的函数看起来像这样:

getUserOrders2(@param.path.number('id') id: number): Promise<Array<OrderFrame>> {
  if (!this.user) throw new HttpErrors.Unauthorized(AuthErrorKeys.ClientInvalid);
  if (this.user.id != id) throw new HttpErrors.Unauthorized(AuthErrorKeys.ClientInvalid);

  return this.restaurantRepository
    .orders(this.user.restaurantId).find().then(
      orders => Promise.all(orders.map(
        order => this.orderRepository.orderItems(order.id).find().then(
          order => new OrderFrame(order)
        )
      ))
    );
}

这个函数的async/await等价物会更复杂。

然后,您将等待调用代码中的结果,无论如何您都必须这样做:

async test() {
  const orders = await foo.getUserOrders2(someUserId);
  // ...
}

// or

test() {
  foo.getUserOrders2(someUserId).then(orders => {
    // ...
  });
}
于 2019-09-30T10:56:42.107 回答