What is an "async relationship"? / `{async: true}` vs. `{async: false}`


#1

The Ember Data API mentions the concept of “async relationships”.
E.g., DS.belongsTo(..) and DS.hasMany(..) both allow to provide a hash with key async:

App.Post = DS.Model.extend({
  comments: DS.hasMany('comment', {async: true})
});

What is the difference of async being either true or false and what consequences does it have on application design?


What is difference between async true/false on a relationship
#3

As far as I know, when async is false Ember will fetch the related entity at the same time as fetching the parent entity. When async is true, it will fetch the related entities when you actually request them.


#4

@Rengers, thank you! Let’s assume in the following that with {async: false}, any related entity will be in fact fetched eagerly (that’s how I understood your words).

Consider the following model/class:

App.User = DS.Model.extend({
  friends: DS.hasMany('user', {async: false})
});

friends is a reflexive association.
So does that mean that in the moment I find the first user with at least one friend, then this kicks off a cascade of recursive requests? E.g., in a big social network application, finding one user results in a million additional requests?


#5

Good question, I’m not sure about that. You can try it and log the requests to see what happens of course ;). Maybe a more experienced Ember Data user can help out here.


#6

The way I learned it was that async: false means that Ember Data expects to already have the related data as part of the original request, and async: true means it will need to make an additional request to get it (but it won’t necessarily make that request automatically).

In a simple relationship, where a User hasMany Stuff,

stuff: DS.hasMany('stuff', {async: false})

then Ember Data is expecting a request for User to get something like this in response:

{
stuff: [ { id: 1, user_id: 1 }, { id: 2, user_id: 1 }, { id: 3, user_id: 1 } ],
user: { id: 1, stuff_id: [1, 2, 3] }
}

but if the relationship was

stuff: DS.hasMany('stuff', {async: true})

then Ember Data is just expecting this:

{
user: { id: 1, stuff_id: [1, 2, 3] }
}

…and if you load the user and ask for user.get('stuff') then it will make a separate request for its related Stuff objects. So it may be more helpful to think of the async: value not as telling Ember Data how to fetch things, but as telling Ember Data how to expect things from the server.

I’ve only recently tangled with this, though, so I’d be happy to be corrected if I have it wrong.


#7

Another thing to take into consideration is that

stuff: DS.hasMany('stuff', {async: true})

will always return a promise when you call myModel.get('stuff'), even if the server sends the data for stuff alongside myModel.

I believe @wycats said that {async: true} will become the default eventually - https://github.com/emberjs/data/issues/1443#issuecomment-26607013


#8

Wonder where I find the downvote button!


#9

Thanks @flashesofpanic, your described behavior is almost* what I observed on Ember 1.3.1 and Ember Data 1.0.0-beta.6:

Given:

App.Post = DS.Model.extend({
  comments: DS.hasMany('comment', {async: true})
});

then a query this.store.find("post", 12345) will result in an HTTP GET request to posts/12345. Ember Data expects as a response something like:

{
  post: {
    id: 12345,
    comments: [457459, 98989898, 3643434]
  }
}

(*… regarding “almost”: I’m using Ember 1.3.1 and Ember Data 1.0.0-beta.6. Notice in my above example, the server’s JSON response is expected to contain a key named comments. A key named comment_id or comments_id doesn’t work to my observation)


#10

Regarding your “almost” - this is actually because you two are using different adapters.

The ActiveModelAdapter expects:

{
  post: {
    id: 12345,
    comment_ids: [457459, 98989898, 3643434]
  }
}

RESTAdapter (the default) expects:

{
  post: {
    id: 12345,
    comments: [457459, 98989898, 3643434]
  }
}

#11

How this works now ?

async for me doesn’t work when I debugging data models on route ?

I’m need to load it the same time one of the data related with my visitor.

This works for me, however maybe there is better solution for that ?

// route file

model(params) {
        return Ember.RSVP.hash({
            visitor: this.get('store').findRecord('visitor', params.id).then(function(visitor){
                return Ember.RSVP.cast(visitor.get('quote')).then(function(){
                    return visitor;
                });
            })
        });
    },