data
data copied to clipboard
The response from accessing hasMany relationship synchronously, block the whole template from doing a kick-start with some init data
We currently update the Ember version to Ember 4 and we also update the ember-data version to 4.4.0 but there is something change that has an impact on my app performance, i will explain
I have a tenant model and this tenant has many catalogs
export default class TenantModel extends Model {
attr('string') something
....
// Relationships
@hasMany('catalog', { async: true})
public catalogs: EmberDataRelation<MutableArray<CatalogModel>>;
}
And the catalog model
export default class CatalogModel extends Model {
attr('string') something
....
// Relationships
@belongsTo('tenant', { async: true })
public tenant: EmberDataRelation<TenantModel>;
}
Since the catalogs call took long from our backend because the response has a lot of data, we included catalogs
prop inside the tenant response, that has an array of all catalogs ids and before the upgrade, ember-data was able to read and load those ids in the catalogs table until the catalogs request finished, the table update with the full catalogs response
So the tenant's response looks like this:
{
id: 1,
...,
catalogs: ['catalogId_1', 'catalogId_2',....]
links: {
catalogs: "/tenants/1/catalogs/"
}
}
For ember-data version 3.27.1 if i access the relationship in synchronous ways, like const catalogs = tenant. catalogs;
i got this:
and accessing the relationship length got the exact length because i think it depends on the list of ids but if I access the catalogs.firstObject
for example, all the entities in the ember record are undefined except the id
so as I understand it, it creates a list of dummy records with the id and as soon the request is finished I got this
For ember-data 4.4.0 if i access the relationship in a synchronous way i got a PromiseManyArray
that is why the template didn't load the ids in the first step:
Description
According to the docs, from ember-data version 3.28.0 this is the default behavior when accessing hasMany relationship 🤔 But from the performance wise, it will be better to have the old behavior of creating a dummy model with ids and those got updated after the response is complete instead of waiting because in our case the catalogs request take time due to the response size, of course, there might be some backend solution for this like pagination for example but we were using this ids list as a workaround solution due to the limited resources to implement a backend solution
Versions
Before I was using these versions
Ember data-> 3.27.1 Ember-cli -> 3.28.2 Ember source -> 3.28.1
Now the current versions I use after the upgrade
Ember data-> 4.4.0 Ember-cli-> 4.4.0 Ember source-> 4.5.0
@usamahamed in 3.27 did you get a links
property on the hasMany?
I'd also note this doesn't have any affect on performance, ember-data would be equally non-blocking in 3.27 and 3.28/4.x for an async relationship. I think from what you are saying you somehow had a situation where you improved perceived performance by having a loading state for each thing with an ID. There is a public API for doing exactly that fwiw (references).
I suspect the change here is probably that somehow you were in a broken state in 3.27 in which the relationship believed it was loaded but accessing it triggered individual loads of each record. When relationship states got improved in 3.28 that bug probably got squashed and now the relationship knows it needs to fire a request (and correctly uses the link to do so). In this scenario it wouldn't be blocking because it thought it was loaded but also it would have been triggering N requests (one per record in the relationship).
@runspired For the first question, do you mean when accessing the relation with hasMany
🤔 ?
For the second part, i am not sure how did i break the state in 3.27 because if yes, it should also not behave correctly in the 3.28/4.x.
What i like about the 3.27 is that they doing something like web optimization to do a critical rendering of something viewable and lazy load the other but in the same context, that is exactly 3.27 doing i think 🤔 because when i access the relation in a synchronous way without await
ember-data create a context of responses which include dummy empty records with the relation's ids and as soon the request done, it updates those records, The meaning of accessing the references API to get the ids and show it until the hasManyArrayPromise
get resolve, that means to me this is blocking since most of our Ember components designed to render ember-data records and it is best that ember-data provide me ids in the same response context to render without explicitly doing that in two steps since it is already available API
But if the Ember-data team thought this new behavior is best for performance, it is okay. it is just a matter of opinions 😉
But if the Ember-data team thought this new behavior is best for performance, it is okay. it is just a matter of opinions
I'm pretty sure this was relying on a bug of some form, and it's definitely not a behavior we want to support, and would lead to a great number of unrecoverable errors and bugs should any individual record fail to load.
The pattern for sync cache access of async data historically has been to peek the cache via the references API. That is still the suggestion here now, though new patterns are likely to be created utilizing more recent Cache APIs in the near future that merge the abilities of references and relationships into a single structure.