解析路由中的键路径(或链式关系)

Resolving keypaths (or chained relationships) in route

我正在处理一堆记录并为第三方库生成一个哈希数组。对于我的生活,我无法弄清楚为什么这不起作用。

export default Route.extend({
  model: function(params) {
   let qp = {viewName: 'byDay'};

  return this.store.query('job-receipt', qp).then(
   (receipts)=>
    all(
      receipts.map(
        (receipt)=>
          hash({
            stockCode: receipt.get('job')
                                   .then(job => job.get('stockCode'))
                                   .then(stockCode => stockCode.get('stockCode')),
            productClass: receipt.get('job')
                                  .then(job => job.get('stockCode'))
                                  .then(stockCode => stockCode.get('productClass'))
                                  .then(productClass => productClass.get('descr')),
            qtyRecvd: receipt.get('qtyRecvd')
          })
        )
      )
);

如果我继续重新进入路线,最终承诺会解决。如果我检查,productClass promise 会直接被调用并返回一个空值。为什么不等待 stockCode.get('productClass') 解决?我知道那里有真正的价值,因为它最终会解决。

我缺少一些非常基本的东西。我试过 Ember.get(thing, keypath) 等。难道这些不是所有 return 的承诺吗?难道 RSVP.hash 不应该等待所有的承诺在继续之前解决吗?就像我说的,我知道数据很好,因为最终它确实解决了(而不是我只是没有处理拒绝)。

编辑:

我将 productClass 承诺更改为:

productClass: receipt.get('job')
        .then(job => job.get('stockCode'))
        .then(stockCode => stockCode.get('productClass'))
        .then(productClass => {if (!productClass) {return 'foo';} return productClass.get('descr');})

现在报告每次都能正确呈现,尽管有一些废话。如果我导航到另一条路线,然后回到这条路线,它会完美呈现。所以,这让我很难相信我有某种数据错误。甚至有些股票代码return对产品class——不是'foo'——就先运行通过。我什至不确定如何进一步调试它。

编辑

刚看到这个。毕竟可能是一个错误。

[3.2.0+] Snapshot 的相关数据变为空#5565

我认为主要问题是 "reciepts.job" 很可能是 DS.belongsTo 关系,对吗?如果您将其切换为加载 job: DS.belongsTo('job', {async: false}),那将强制 ember-data 同步加载 属性(并且会省去很多麻烦)。但这要求数据在 json 响应中可用。

如果这不起作用,您应该调查 ember concurrency。使用它来清理您的代码,使其看起来更直接一些。您必须填写一些空白或更改我误解了您的用例的内容,但这可能是一个很好的起点。

想法是继续将所有异步调用分解为单独的任务。每个 ember-并发 task 对象 return 都是一个承诺,因此您可以继续将它们捆绑在一起,直到达到 model,您可以像其他任何对象一样 return承诺。

//model.js
import {task} from 'ember-concurrency';
.....

model() {
  return this.get('loadData').perform();
},
loadData: task(function*(){
  let reciepts = yield this.store.query('job-receipt', qp);
  let promises = reciepts.map(r => {
    return this.get('loadNestedData').perform(r);
  })
  return all(promises)
}),
loadNestedData: task(function*(reciept) {
  let job = yield receipt.get('job');
  return hash({
    stockCode: job.get('sockcode')
  });
})

原来是个bug。 belongs-to.js 的错误导致模型在解决承诺之前不等待 internalModel 完成加载。下面链接的修复解决了这个问题

[BUGFIX] use internalModel promise if already loading #5562