Where is the best place to initialize things before ember is ready?


#1

I was trying to figure out where the best place in an Ember app was to do things such as set up a WebSQL database connection, ensure SQL schema is defined, have Facebook SDK determine if a user is logged in, etc. I was not sure if

Ember.Application.create({
  initialize: function(container, application) {
    container.register('db', function() {
      deferReadiness()
      // database setup code
      advanceReadiness();
      // return database connection
    });
    container.register('facebook', function() {
      deferReadiness()
      // facebook sdk initialization code here
      advanceReadiness();
      // return Facebook sdk instance
    });
  }
});

was the best place to handle such non-ember related setup code. I was also considering beforeModel on the application router or controller. Or is deferReadiness() and advanceReadiness() the way to go, and if so, where/how would those methods be used? Preferably, I would prefer to be able to do setup things like WebSQL database setup and Facebook SDK stuff asynchronously. If different setup tasks were called asynchronously, what would be a good way to ensure all of the async functions were finished before the application would be considered ready?

So many questions. Any suggestions.


#2

I am going to take a stab at answering my own question. Granted I don’t know if this is a good way of doing things. I just know that this seems to work.

    App = Ember.application.create();
    var setDB = function() {
      return new Promise(function(resolve, reject) {
        setTimeout(function() { // this is only to simulate a delay
          console.log('database ready to go');
          resolve('db connection goes here');
        }, Math.floor(Math.random()*5000));
      });
    };
    var setFB = function() {
      return new Promise(function(resolve, reject) {
        setTimeout(function() {
          console.log('facebook ready to go');
          resolve('facebook value goes here');
        }, Math.floor(Math.random()*5000));
      });
    };
    
    App.deferReadiness();
    Promise.all([setDB(), setFB()]).then(function() {
      console.log('promises resolved. ready to go');
      App.advanceReadiness();
    });

It is possible that there could be a typo in this code since I translated it from coffeescript. I would love any feedback that anyone has on this technique.


#3

What you did in the second post is the pattern we have been following.


#4

That’s good to hear. I was just guessing how to do this. I could not find any documented way to do setup.


#5

You can use Ember.Application.initializer for this purpose. Initializers consits of their name, the after and before property (which declares if the initializer is run before/after another initializer) and the initialize() function:

Ember.Application.initializer({
  name: 'init_db',

  initialize: function (container, application) {
    application.deferReadines();
     // your db init code here
  }
});


Ember.Application.initializer({
  name: 'init_fb',

  after: 'init_db',

  initialize: function (container, application) {
     // your fb init code here
    application.advanceReadines();
  }
});

Within the initializer you can also make use of the given container and register/inject dependencies, etc. For more information about Ember.Application.initializers see:


#6

herom, thanks for that. I refactored my code to use this approach. Defining initializers looks like the way to go.


#7

you’re welcome @mrinterweb :smiley_cat:

I myself am struggling with initializing things using the EAK and I came along the initializers… sadly they seem not to be well documented…


#8

Just remember to not use initializers for preloading data into the store, because then the whole app won’t be rendered until your callback is done, which could be either 15 seconds from now or a minute. If you want your app to feel snappy, then you should never put your users on hold. It’s like using the sync flag in Node.

best to handle this use case at the route level, (router stops for promises, you can manually push records into the store) where at the very least your application template will be drawn and you can show a (eew) loading.


#9

Good advice. My first pass with the initializers was forcing promises to be resolved before advancing the app. That said, I am in the process now of removing those blocking promises that I was forcing earlier. I’d much rather show loading than an uninitialized app.


#10

Put it inside your application route, in a hook that stops for promises (beforeModel model, afterModel. Does activate stop for promises too?.) Use something like SetupMixin to keep things clean and testable. I’m guessing that you should be in LoadingRoute while this all gets going.

The problem then is that you are still blocking the user experience. No one likes waiting for anything to setup. Gotta get the users permission before you put them on hold. But that’s more of a UX problem.


#11

For the db connection stuff, I’d use ember-data. Wires everything up together out of the box. For the facebook sdk stuff, is that to see if there’s a current user or something? Maybe you can just call that in the background and hook an observer to it?