Ember 2,在 API 响应中使用包含的关系时,isPending、isSettled、isFulfilled 的奇怪行为
Ember 2, Strange behaviour with isPending, isSettled, isFulfilled when using included relationships in API response
我需要一次搞清楚为什么属性喜欢
isSettled
isPending
isFulfilled
如果我在 API 回复中包含或不包含数据,情况会有所不同。
我在这里问这个:https://discuss.emberjs.com/t/ember-2-show-a-single-loading-message-when-the-ids-where-included-in-the-original-response/12654 这导致我出现这种奇怪的行为:
如果我在我的 API 响应中包含数据(例如:model.posts
),这些属性会立即设置为 true(并且 .isPending
为 false)如果 Chrome 还在加载真实数据(也是第一次!)。
这是一个问题,因为我不知道 posts[] 是否为空,而且我不知道我可以窥探什么,因为类似的东西不会不工作:
{{#each model.posts}}
My posts.
{{else}}
{{#if model.posts.isPending}}
<div>Loading...</div>
{{else}}
<div>Nothing to show.</div>
{{/if}}
{{/each}}
它总是 "Nothing to show.",直到 Chrome 加载。因为 .isPending
立即 false.
此外,如果我使用 length 属性:
{{#if (eq model.posts.length 0)}}
因为起始 posts[] 数组和空数组的长度始终为 == 0。
如果我以不同的方式加载帖子,异步的,而不是旁加载的(但有数百个 HTTP 请求,我不想要)它会起作用。 Ember 认识一个 isPending
...
为什么会出现这种奇怪的行为?
更新
我对 /category/1 的 API 回复:
{
"data": {
"id": "1",
"type": "categories",
"attributes": {
"name": "Book"
},
"relationships": {
"posts": {
"data": [{
"id": "11",
"type": "posts"
}, {
"id": "14",
"type": "posts"
}, {
"id": "16",
"type": "posts"
}]
}
}
},
"included": [{
"id": "11",
"type": "posts",
"attributes": {
"style": false,
"comments": true
}
}, {
"id": "14",
"type": "posts",
"attributes": {
"style": true,
"comments": false
}
}, {
"id": "16",
"type": "posts",
"attributes": {
"style": true,
"comments": false
}
}]
}
因为我在 Rails 控制器中使用 include。
其他策略?
嵌入式:ids?
JSON API 链接?
怎么办?
我唯一的可怜的小宝宝问题:
我不想要很多很多 HTTP 请求。只有一个用于类别(模型),一个(非阻塞,带有加载消息)用于在第一个模型(类别)之后的帖子...
好的,我想我需要先告诉您加载数据的不同方式。在您的示例中,您有两个模型。我知道一个叫 post
,现在我们叫另一个 my-model
.
现在他们之间建立了 to-many 关系。在my-model
中大概是这样的:
posts: hasMany('post'),
现在显然您想要显示给定 my-model
的所有 post
。为此,您可能有一条像 /my-model-posts/:myModel_id
这样的路线。一个很有趣的问题是你如何link到这条路线。这是因为对于 link 您已经需要 my-model
实例,现在的问题是您如何加载它...
我稍后会讨论这个,现在让我们假设您的用户在给定 url 时直接点击您的应用程序,因为这是您始终必须处理的 use-case。
因为命名约定 model_id
你不必自己写你的路线。但是请记住,默认实现等效于此显式路由定义:
model(params) {
return this.store.findRecord('my-model', params.myModel_id);
}
现在后台基本上有3种响应方式:
旁加载所有内容
{
data: {
type: 'my-model',
id: 'foo',
attributes: {...},
relationships: {
posts: {
data: [{
type: 'post',
id: '1'
},{
type: 'post',
id: '2'
}]
}
}
},
included: [{
type: 'post',
id: '1',
attributes: {...}
}, {
type: 'post',
id: '2',
attributes: {...}
}]
}
旁加载 ID
{
data: {
type: 'my-model',
id: 'foo',
attributes: {...},
relationships: {
posts: {
data: [{
type: 'post',
id: '1'
},{
type: 'post',
id: '2'
}]
}
}
}
}
使用相关的link
{
data: {
type: 'my-model',
id: 'foo',
attributes: {...},
relationships: {
posts: {
links: {
related: '/api/model/foo/posts'
}
}
}
}
}
现在您需要了解由 findRecord
编辑的承诺 return 将等待服务器的第一次响应然后解析。您的路由器 将在进入路由 之前等待此响应。理解这一点非常重要:在这个承诺解决之前,您的路线不会被输入。要指示此阶段的加载状态,您可以使用 a loading substate..
因此对于第一个示例,如果您侧载所有内容,这就足够了。请记住,当响应为 returned 时,没有更多数据要加载。此外,在加载此响应之前,您处于加载子状态。
最后一个例子也不是很难。一种简单的方法是显示两个加载微调器。你需要这个,因为你发出了两个请求并且处于两个加载状态:
- 用户点击路线
- 您提出
findRecord
请求
- 加载子状态一直显示到
findRecord
请求完成
- 响应已 returned,模板将被渲染
- 您访问
model.posts
,这将触发相关的 link 加载。加载数据时 model.posts.isPending
将是 true
。可以用一个简单的{{#if model.posts.isPending}}loading...{{/if}}
来表示加载状态
- 响应已 returned,
model.posts.isPending
现在是 false
。现在已加载所有数据。
但是,如果需要,您可以通过修改将其减少到一个单一的加载状态。您可以在 afterModel
hook:
中加载 post
s
afterModel(model) {
return model.get('posts');
}
这将强制执行承诺 posts
在进入路线之前加载,让您保持在 loading substate.
另一种是直接加载posts,如果你不关心my-model
实例:
model(params) {
return this.store.findRecord('my-model', params.myModel_id)
.then(m => m.get('posts'));
}
现在 model
将成为您的 posts 数组,您将一直处于加载子状态,直到 posts 被加载。
最后但同样重要的是让我们谈谈第二个例子:你只侧载 id
s。这可能是最棘手的一个。如果你只侧加载 id
s,你没有单个 属性 表示 something 仍然被加载。这是因为有很多 HTTP 请求,以及很多表明某些内容仍在加载的承诺。可能唯一的 use-case 是当您真正想尽快向用户显示数据时,所以我建议 loading-spinner 每个 post:
{{#each model.posts as |post|}}
{{#if post.isLoading}}
loading...
{{else}}
...the data...
{{/if}}
{{else}}
no posts
{{/each}}
请注意,如果您没有 posts,那么在您必须发出单个 HTTP 请求之前,这是您知道的事情!
如果你想要一个单一的加载微调器,你可以在 my-model
:
上创建一个计算的 属性
hasLoadingPosts: Ember.computed('posts.@each.isLoading', {
get() {
return this.get('posts').any(post => post.get('isLoading'));
}
})
您也可以将其保留在加载子状态中,但这有点棘手:
afterModel(model) {
return model.get('posts')
.then(posts => Ember.RSVP.all(posts.toArray()));
}
您可以在 model
挂钩中做类似的事情:
model(params) {
return this.store.findRecord('my-model', params.myModel_id)
.then(m => m.get('posts'))
.then(posts => Ember.RSVP.all(posts.toArray()));
}
另请注意,最后两个 promise-handling JS-snippets 适用于所有场景。如果数据已经加载,它们不会造成伤害,但会等待相关的 link 以及旁加载的 ID。
现在需要注意的一件非常重要的事情是通常不会direct-link到这样的页面。可能你在某个地方有一个 my-model
或其他东西的列表,然后是一个 link-to
来显示 post。 在这里你不会碰到model
钩子!你也不需要第一个请求:my-model
的数据已经在商店里了!现在的问题是,当您首先加载它时 return 编辑了什么。您是否侧载了所有内容,只有 id
或使用了相关的 link?结果和上面的场景差不多!
如果您修改了 model
挂钩,您可能也应该更改 link-to
,从 {{#link-to 'my-model-posts' model}}
更改为 {{#link-to 'my-model-posts' model.posts}}
。这很奇特,因为如果你使用了相关的 link 路由将再次等待这个 promise 的解析。
通常我的建议是永远不要仅下载 ID。这也可能仅在您不为后端使用关系数据库时才有用。
我建议使用相关的 links 并在极少数情况下旁加载所有内容。例如,如果你直接加载 my-model
我会旁加载所有内容,并且仅针对列表 return 相关的 links.
现在只要编程,因为只有 related
link,事情通常会正常工作。如果您有时需要较少的加载指示器,这很好。
此外,如果您只显示这个 post 数组,我会更改路由的语义,并在 model
挂钩的数组中直接 return this。当然,然后如上所述更改 link-to
s。
但是,如果您想显示 my-model
的某些数据(如标题),可能需要尽快显示它们。此处显示标题时需要 isPending
,但还没有 post。
但是,如上文所述,当您仅侧载 id
时,这两种解决方案 都会中断。
我需要一次搞清楚为什么属性喜欢
isSettled
isPending
isFulfilled
如果我在 API 回复中包含或不包含数据,情况会有所不同。
我在这里问这个:https://discuss.emberjs.com/t/ember-2-show-a-single-loading-message-when-the-ids-where-included-in-the-original-response/12654 这导致我出现这种奇怪的行为:
如果我在我的 API 响应中包含数据(例如:model.posts
),这些属性会立即设置为 true(并且 .isPending
为 false)如果 Chrome 还在加载真实数据(也是第一次!)。
这是一个问题,因为我不知道 posts[] 是否为空,而且我不知道我可以窥探什么,因为类似的东西不会不工作:
{{#each model.posts}}
My posts.
{{else}}
{{#if model.posts.isPending}}
<div>Loading...</div>
{{else}}
<div>Nothing to show.</div>
{{/if}}
{{/each}}
它总是 "Nothing to show.",直到 Chrome 加载。因为 .isPending
立即 false.
此外,如果我使用 length 属性:
{{#if (eq model.posts.length 0)}}
因为起始 posts[] 数组和空数组的长度始终为 == 0。
如果我以不同的方式加载帖子,异步的,而不是旁加载的(但有数百个 HTTP 请求,我不想要)它会起作用。 Ember 认识一个 isPending
...
为什么会出现这种奇怪的行为?
更新
我对 /category/1 的 API 回复:
{
"data": {
"id": "1",
"type": "categories",
"attributes": {
"name": "Book"
},
"relationships": {
"posts": {
"data": [{
"id": "11",
"type": "posts"
}, {
"id": "14",
"type": "posts"
}, {
"id": "16",
"type": "posts"
}]
}
}
},
"included": [{
"id": "11",
"type": "posts",
"attributes": {
"style": false,
"comments": true
}
}, {
"id": "14",
"type": "posts",
"attributes": {
"style": true,
"comments": false
}
}, {
"id": "16",
"type": "posts",
"attributes": {
"style": true,
"comments": false
}
}]
}
因为我在 Rails 控制器中使用 include。
其他策略?
嵌入式:ids?
JSON API 链接?
怎么办?
我唯一的可怜的小宝宝问题:
我不想要很多很多 HTTP 请求。只有一个用于类别(模型),一个(非阻塞,带有加载消息)用于在第一个模型(类别)之后的帖子...
好的,我想我需要先告诉您加载数据的不同方式。在您的示例中,您有两个模型。我知道一个叫 post
,现在我们叫另一个 my-model
.
现在他们之间建立了 to-many 关系。在my-model
中大概是这样的:
posts: hasMany('post'),
现在显然您想要显示给定 my-model
的所有 post
。为此,您可能有一条像 /my-model-posts/:myModel_id
这样的路线。一个很有趣的问题是你如何link到这条路线。这是因为对于 link 您已经需要 my-model
实例,现在的问题是您如何加载它...
我稍后会讨论这个,现在让我们假设您的用户在给定 url 时直接点击您的应用程序,因为这是您始终必须处理的 use-case。
因为命名约定 model_id
你不必自己写你的路线。但是请记住,默认实现等效于此显式路由定义:
model(params) {
return this.store.findRecord('my-model', params.myModel_id);
}
现在后台基本上有3种响应方式:
旁加载所有内容
{
data: {
type: 'my-model',
id: 'foo',
attributes: {...},
relationships: {
posts: {
data: [{
type: 'post',
id: '1'
},{
type: 'post',
id: '2'
}]
}
}
},
included: [{
type: 'post',
id: '1',
attributes: {...}
}, {
type: 'post',
id: '2',
attributes: {...}
}]
}
旁加载 ID
{
data: {
type: 'my-model',
id: 'foo',
attributes: {...},
relationships: {
posts: {
data: [{
type: 'post',
id: '1'
},{
type: 'post',
id: '2'
}]
}
}
}
}
使用相关的link
{
data: {
type: 'my-model',
id: 'foo',
attributes: {...},
relationships: {
posts: {
links: {
related: '/api/model/foo/posts'
}
}
}
}
}
现在您需要了解由 findRecord
编辑的承诺 return 将等待服务器的第一次响应然后解析。您的路由器 将在进入路由 之前等待此响应。理解这一点非常重要:在这个承诺解决之前,您的路线不会被输入。要指示此阶段的加载状态,您可以使用 a loading substate..
因此对于第一个示例,如果您侧载所有内容,这就足够了。请记住,当响应为 returned 时,没有更多数据要加载。此外,在加载此响应之前,您处于加载子状态。
最后一个例子也不是很难。一种简单的方法是显示两个加载微调器。你需要这个,因为你发出了两个请求并且处于两个加载状态:
- 用户点击路线
- 您提出
findRecord
请求 - 加载子状态一直显示到
findRecord
请求完成 - 响应已 returned,模板将被渲染
- 您访问
model.posts
,这将触发相关的 link 加载。加载数据时model.posts.isPending
将是true
。可以用一个简单的{{#if model.posts.isPending}}loading...{{/if}}
来表示加载状态 - 响应已 returned,
model.posts.isPending
现在是false
。现在已加载所有数据。
但是,如果需要,您可以通过修改将其减少到一个单一的加载状态。您可以在 afterModel
hook:
post
s
afterModel(model) {
return model.get('posts');
}
这将强制执行承诺 posts
在进入路线之前加载,让您保持在 loading substate.
另一种是直接加载posts,如果你不关心my-model
实例:
model(params) {
return this.store.findRecord('my-model', params.myModel_id)
.then(m => m.get('posts'));
}
现在 model
将成为您的 posts 数组,您将一直处于加载子状态,直到 posts 被加载。
最后但同样重要的是让我们谈谈第二个例子:你只侧载 id
s。这可能是最棘手的一个。如果你只侧加载 id
s,你没有单个 属性 表示 something 仍然被加载。这是因为有很多 HTTP 请求,以及很多表明某些内容仍在加载的承诺。可能唯一的 use-case 是当您真正想尽快向用户显示数据时,所以我建议 loading-spinner 每个 post:
{{#each model.posts as |post|}}
{{#if post.isLoading}}
loading...
{{else}}
...the data...
{{/if}}
{{else}}
no posts
{{/each}}
请注意,如果您没有 posts,那么在您必须发出单个 HTTP 请求之前,这是您知道的事情!
如果你想要一个单一的加载微调器,你可以在 my-model
:
hasLoadingPosts: Ember.computed('posts.@each.isLoading', {
get() {
return this.get('posts').any(post => post.get('isLoading'));
}
})
您也可以将其保留在加载子状态中,但这有点棘手:
afterModel(model) {
return model.get('posts')
.then(posts => Ember.RSVP.all(posts.toArray()));
}
您可以在 model
挂钩中做类似的事情:
model(params) {
return this.store.findRecord('my-model', params.myModel_id)
.then(m => m.get('posts'))
.then(posts => Ember.RSVP.all(posts.toArray()));
}
另请注意,最后两个 promise-handling JS-snippets 适用于所有场景。如果数据已经加载,它们不会造成伤害,但会等待相关的 link 以及旁加载的 ID。
现在需要注意的一件非常重要的事情是通常不会direct-link到这样的页面。可能你在某个地方有一个 my-model
或其他东西的列表,然后是一个 link-to
来显示 post。 在这里你不会碰到model
钩子!你也不需要第一个请求:my-model
的数据已经在商店里了!现在的问题是,当您首先加载它时 return 编辑了什么。您是否侧载了所有内容,只有 id
或使用了相关的 link?结果和上面的场景差不多!
如果您修改了 model
挂钩,您可能也应该更改 link-to
,从 {{#link-to 'my-model-posts' model}}
更改为 {{#link-to 'my-model-posts' model.posts}}
。这很奇特,因为如果你使用了相关的 link 路由将再次等待这个 promise 的解析。
通常我的建议是永远不要仅下载 ID。这也可能仅在您不为后端使用关系数据库时才有用。
我建议使用相关的 links 并在极少数情况下旁加载所有内容。例如,如果你直接加载 my-model
我会旁加载所有内容,并且仅针对列表 return 相关的 links.
现在只要编程,因为只有 related
link,事情通常会正常工作。如果您有时需要较少的加载指示器,这很好。
此外,如果您只显示这个 post 数组,我会更改路由的语义,并在 model
挂钩的数组中直接 return this。当然,然后如上所述更改 link-to
s。
但是,如果您想显示 my-model
的某些数据(如标题),可能需要尽快显示它们。此处显示标题时需要 isPending
,但还没有 post。
但是,如上文所述,当您仅侧载 id
时,这两种解决方案 都会中断。