Asynchronous Template Loading

I don’t know, how many of you are developing huge applications with Ember.js where it’s necessary to load the Handlebars Templates from the backend on demand because there are a) quite a few hundred templates and b) a bunch of internationalization files which have a few thousand translations per file and therefore if it’s worth mentioning, but we now have the Async Router and other cool stuff so, would it also be possible to load templates asynchronously into Ember.TEMPLATES cache through a custom Resolver object which will work with Promises/Ember.Deferred/Ember.RSVP?

I know I asked a similar question some time ago when Ember was still on rc3, but as I saw the project growing and hardening, I wonder if it’s possible now?

Currently, I have a App.TemplateManager Class which fetches the desired templates from the backend server with a sync Ajax request and is called from Resolver.resolveTemplate:

Resolver: Ember.DefaultResolver.extend({
    /**
     * Overrides the default `resolveTemplate` method of the `Ember.DefaultResolver` class
     * and implements the `App.TemplateManager` for retrieving the precompiled
     * Handlebars templates from the server and integrating it into the `Ember.TEMPLATES` Array.
     *
     * @method resolveTemplate
     * @param {Object}    parsedName
     * @returns {Object}  The template from the `Ember.TEMPLATES` template cache.
     */
    resolveTemplate: function (parsedName) {
      // if however the parsedName.type is not 'template' exit now
      if (parsedName.type !== 'template') {
        return undefined;
      }

      var templateName = parsedName.fullNameWithoutType.replace(/\./g, "/");

      // fetch a "root" template if the templateName is "main" or "user"
      if (templateName.indexOf("/") < 0 && templateName !== 'application') {
        templateName = App.TemplateManager.fetchTemplate(templateName + "/root", templateName);
      } else {
        templateName = App.TemplateManager.fetchTemplate(templateName);
      }

      return Ember.TEMPLATES[templateName];
    }
  })

But I’m forced to use synchronous loading as otherwise I’ll get errors over and over because the Ember.TEMPLATES cache is called immediately… is there a way to achieve this or is it still not possible?

2 Likes

Templates (and code in general) can be loaded asynchronously by taking advantage of Ember’s asynchronous routing.

Return a promise from one of your model hooks (like beforeModel). Resolve the promise after you have everything loaded that you’ll need for the route.

thanks a lot for your reply - I appreciate it a lot! so, if I get you right, it’s possible to return a promise from beforeModel which gets resolved once my template is loaded? if that’s the case, isn’t the promise delaying the rendering of the view the same way as it’s now delayed when I load it with synchronous Ajax?

the reason why I’m asking is, that it’s often the case that a view consists of few templates where some of them could happen to be already loaded into Ember.TEMPLATES cache, where others have to be still loaded from the backend. so I’m seeking for a solution where I’m able to render the view even if not all of the templates are present at the time and render them once they are received from the backend.

I don’t know if I can express myself the way I mean it, but I try to do my best :smiley:

That’s correct – my suggestion would block rendering of each route until all its templates are available. Which is not that different from what you’re suggesting – it’s just a question of whether we show a partially-rendered page for a while, or whether we render everything at once. The total delay is the same (or may even be faster if we coalesce all the rendering into one final step).

Finer-grained partial rendering is possible, but you’d need manage it yourself. You could create container views that initially have nothing in them, and then as templates become available push child views into the containers. But I think this actually gives a worse user experience in many cases. You would need to be careful to keep the page from jumping around surprisingly as various child views pop into existence.

You may also be able to identify things like what translation the user wants right at the server, and serve them a dedicated asset bundle that contains exactly what they’ll need. This may give the best performance, because it means far fewer HTTP requests.

I see, thanks for clearing things out! as far as I can tell now it could be that it’s maybe better to precompile some of the templates (which are commonly used) beforehand and deliver them with the application code (which would lead to another problem with my current implementation of internationalization, but that’s another story), and stay with the synchronous template loading for all other templates…

Do you have any example how to implement the lazy loading of templates?