ember.js Js:并行加载父模型和子模型

bz4sfanl  于 2022-11-05  发布在  其他
关注(0)|答案(1)|浏览(192)

我有这些路线:

  • 职位
  • 索引(所有帖子)
  • single(使用动态参数 post_id
  • 索引(单个帖子及其评论视图)
  • 编辑(编辑帖子)

有两个单独的请求,分别是按ID获取帖子和按帖子ID获取帖子评论。我想并行加载posts.single.index路由的帖子和评论,因为我在路由名称中有一个帖子ID,我不必等待帖子加载。
但是Ember加载帖子。单个模型,并且只有在帖子加载评论之后。
是否可以与父模型并行调用子模型?
我已经找到了一个解决方案,当posts.single不加载任何东西,并且posts.single.index在它自己的模型中调用两个请求时。另一方面,我应该在所有posts.single子路由中加载post模型,例如posts.single.edit。这可能是一个问题,当应用程序增长时。

qv7cva1a

qv7cva1a1#

有几种技术可以在model-Hook of a Route中加载多个资源。哪种技术最适合您的需求,甚至可能高度依赖于您的应用程序。特别是后端API的功能,以及您的Ember应用程序是否使用Ember Data或普通的fetch/ AJAX 请求,会产生很大的差异。
最简单的情况是将Ember Data与遵循JSON:API specification并支持包含相关资源的REST API一起使用:

import Route from '@ember/routing/route';

export default Route.extend({
  model({ post_id }) {
    return this.store.findRecord('post', post_id, { include: 'comments' });
  }
});

如果您使用的是普通fetch,则可以使用Promise.all()并行加载多个记录:

import Route from '@ember/routing/route';

export default Route.extend({
  async model({ post_id }) {
    let [post, comments] = await Promise.all([
      fetch(`/posts/${post_id}`),
      fetch(`/posts/${post_id}/comments`),
    ]);
    return { post, comments };
  }
});

如果你不喜欢Promise.all()的数组析构语法,你可能想看看RSVP.hash()rsvp默认与ember捆绑在一起。
如果使用Ember Data,但您的API不支持侧加载,那么需要使用查询来加载注解,这就有点麻烦了。这取决于您的适配器配置,但我猜它看起来像这样:

import Route from '@ember/routing/route';

export default Route.extend({
  async model({ post_id }) {
    let [post, comments] = await Promise.all([
      this.store.findRecord('post', post_id),
      this.store.query('comment', {
        filter: {
          post: post_id
        }
      })
    ]);
    return { post, comments };
  }
});

不能使用多个model-Hook并行加载资源。父路由和子路由的model-Hook按设计顺序执行。在解析其父路由的model-Hook返回的Promise之前,不会触发子路由的model-Hook。尽管如此,仍然存在仅加载所需数据和缓存在不同子路由之间共享的数据的技术。
让我们从问题和注解中更详细地举你的例子来这样回答:我们的前端应该显示一个帖子,包括它在一个路线上的评论和一个表单,以编辑另一个路线上的同一个帖子。两个路线需要相同的帖子资源,但只有一个还需要帖子的评论。应用程序不应该再次加载后,如果用户从一个路线转换到另一个,如果用户转换到编辑视图,不应该加载评论。
一个幼稚的尝试是一个加载post资源的父路由和两个子路由,一个用于包含注解的视图,一个用于编辑表单。我称这种尝试为“幼稚”,因为它在三个方面失败:
1.帖子和评论不会并行加载。
1.如果用户通过第三个路径在两个路径之间转换,则不会缓存资源。
1.它将可视化设计与数据加载相结合。
第三点可能会令人困惑。事实上,这是Ember中对嵌套路径的一个常见误解。它们 * 不是 * 用于建模数据层次结构,而是应该用于在子路径之间共享可视化UI。重要的不是model-Hook,而是父模板{{outlet}}中的子模板的呈现。
您所关心的所有问题都可以通过一个在客户端缓存资源的服务来轻松解决。这是Ember Data的主要特性之一。这也是Apollo客户端for GraphQL最受欢迎的特性之一。就这么简单:大多数复杂的前端应用程序都需要一个客户端缓存层来防止资源的过度获取。如果你面临这个要求,我建议你使用现有的解决方案之一。对于简单的用例,你也可以构建自己的服务。一个基本的实现可以看起来像这样:

import Service from '@ember/service';

export default class StoreService extend Sevice({
  postCache = new Map();

  loadPost(id) {
    let { postCache } = this;
    if (postCache.has(id)) {
      return postCache.get(id);
    }

    let request = fetch(`/posts/${id}`);
    postCache.set(id, request);
    return request;
  }
});

相关问题