Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ember.js/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 余烬正在等待关系加载到具有余烬并发性的数组中_Javascript_Ember.js_Ember Data - Fatal编程技术网

Javascript 余烬正在等待关系加载到具有余烬并发性的数组中

Javascript 余烬正在等待关系加载到具有余烬并发性的数组中,javascript,ember.js,ember-data,Javascript,Ember.js,Ember Data,我试图根据模型对象的一个相关模型对模型对象数组进行排序 我有一个文档,其中有许多行项目,还有一个行项目位于位置。我想按行项目的位置对其进行排序。如果我有这样的东西: let lineItems = [ { itemName: "One", location: { name: "Kitchen" } }, { itemName: "Two", location: { name: "Kitchen" } },

我试图根据模型对象的一个相关模型对模型对象数组进行排序

我有一个文档,其中有许多行项目,还有一个行项目位于位置。我想按行项目的位置对其进行排序。如果我有这样的东西:

let lineItems = [
  {
    itemName: "One",
    location: {
      name: "Kitchen"
    }
  },
  {
    itemName: "Two",
    location: {
      name: "Kitchen"
    }
  },
  {
    itemName: "Three",
    location: {
      name: "Bathroom"
    }
  },
  {
    itemName: "Four",
    location: {
      name: "Bathroom"
    }
  },
  {
    itemName: "Five",
    location: {
      name: "Hall"
    }
  },
  {
    itemName: "Six",
    location: {
      name: "Hall"
    }
  }
];
我想谈谈:

let groupedLineItems = {
  "Kitchen": [
    {
      itemName: "One",
      location: "Kitchen"
    },
    {
      itemName: "Two",
      location: "Kitchen"
    },
  ],
  "Bathroom": [
    {
      itemName: "Three",
      location: "Bathroom"
    },
    {
      itemName: "Four",
      location: "Bathroom"
    },
  ],
  "Hall": [
    {
      itemName: "Five",
      location: "Hall"
    },
    {
      itemName: "Six",
      location: "Hall"
    }
  ]
}
我已经知道了如何排序,但只有在所有关系加载之后。我不知道如何使用ember并发在对数据排序之前等待所有关系加载

这是我的控制器:

~/app/controllers/document.js

import Ember from 'ember';
import _ from 'underscore';
import { task } from 'ember-concurrency';
const { computed } = Ember;

export default Ember.Controller.extend({
    init() {
        this.get('myTask').perform();
    },

    myTask: task(function * () {
        // Wait for locations to resolve.
        let lineItems = this.get('model').get('lineItems');

        yield this.get("secondTask").perform(lineItems);

        let groupedLineItems = yield _.groupBy(lineItems.toArray(), (lineItem) => {
            lineItem.get('location').then((location) => {
                return location.get('name');
            });
        });

        this.set("groupedLineItems2", Ember.Object.create(groupedLineItems));
    }),

    secondTask: task(function * (lineItems) {
        yield lineItems.toArray().forEach((lineItem) => {
            lineItem.get('location');
        });
    })
});
这是控制器上的WIP,不正确。在init上,第一个任务运行,但不等待为每个行项目加载位置。我试图让它加载第二个任务中的所有位置,但这显然不是正确的方法。因此,在init上,它将运行排序,但是u.groupBy的函数将返回undefined,因为此时位置未定义。然后,如果我在知道位置已加载(因为我在模板的其他位置使用它们)后再次手动运行任务(使用模板上的按钮),则可以正常工作

解决方案不必使用ember并发,它看起来是正确的工具,但我认为它也可以通过承诺来实现。

好问题

我会这样做的

models/document.js

import Ember from 'ember';
import Model from "ember-data/model";
import attr from "ember-data/attr";
import { belongsTo, hasMany } from "ember-data/relationships";

export default Model.extend({
  lineItems: hasMany('line-item'),

  groupedLineItemsPromise: Ember.computed(function () {
    return this
      .get('lineItems')
      .then(lineItems => {
        const locations = Ember.RSVP.all(lineItems.map(item => item.get('location')))
        return Ember.RSVP.hash({lineItems, locations})
      })
      .then(({lineItems}) => {
        return lineItems.reduce((result, item) => {
          const locationName = item.get('location.name')
          result[locationName] = result[locationName] || []
          result[locationName].pushObject(item)
          return result
        }, {})
      })
  }),

  groupedLineItemsProxy: Ember.computed('groupedLineItemsPromise', function () {
    return Ember
      .Object
        .extend(Ember.PromiseProxyMixin)
        .create({
        promise: this.get('groupedLineItemsPromise')
      })
  })
});
演示:

请注意,您并不真正需要
ember并发性
。我使用良好的旧计算属性来实现结果

但问题是,这首先是错误的方法,
ember并发
与否:

  • 这种方法将生成大量的网络请求,除非您使用的分组网络请求(并且您的后端支持这一功能)的文档记录不足
  • 如果任何请求失败,您的应用程序将进入不一致状态。整个并发任务/计算属性可能会失败,用户将没有机会重新启动失败的请求
  • 您的页面将过早呈现,没有内容。然后内容最终会出现
  • 当然,这三个问题都可以解决,但这是一个PITA正确的方法是在路由的模型挂钩中预加载关系。

    以这样一种方式组织它:只需几次网络请求即可获取所有必要的记录。要么使用JSONAPI过滤器,要么创建一个服务于所有相关记录的自定义API端点


    在最坏的情况下,仍然会执行大量请求,但在路由的模型钩子中执行,该钩子将负责异步并将记录(而不是承诺)馈送到控制器/模板中一旦相关记录被预加载,您就可以像同步一样访问关系

    这不是“排序”。谢谢,这是一个很好的答案!最后我意识到我需要这样做:
    返回this.get('store').findRecord('document',params.document_id,{include:'lineItems.location'})在我的模型钩子上的路线。然后我可以做:
    groupedLineItems:computed('model.lineItems.@each.location',function(){const lineItems=this.get('model').get('lineItems').toArray();返回这个.sortObject(u.groupBy(lineItems,(lineItem)=>lineItem.get('location').get('name');}