     , @options().timestamp_refresh_interval)
 
   init: ->
-    initializer = @createCallback 3, =>
-      Kandan.registerPlugins()
+    asyncInitializers = [
+      (callback) => new Kandan.Collections.Channels().fetch { success: @onFetchChannels(callback) }
+      (callback) => new Kandan.Collections.ActiveUsers().fetch { success: @onFetchActiveUsers(callback) }
+      (callback) => new Kandan.Collections.Users().fetch { success: @onFetchUsers(callback) }
+    ]
+    # The initializer callback should only be called after all
+    # asynchronous initialization has been completed.
+    syncInitializer = @callAfter asyncInitializers.length, =>
+      @registerPlugins()
       Kandan.Plugins.initAll()
-      Kandan.initChatArea(Kandan.Helpers.Channels.getCollection())
-      Kandan.initTabs()
+      @initChatArea(Kandan.Helpers.Channels.getCollection())
+      @initTabs()
       Kandan.Widgets.initAll()
       Kandan.Helpers.Channels.scrollToLatestMessage()
       Kandan.Plugins.Mentions.initUsersMentions(Kandan.Helpers.ActiveUsers.all())
       Kandan.Plugins.Emojis.attachToChatbox()
-      return
 
-    new Kandan.Collections.Channels().fetch {
-      success: @onFetchChannels(initializer)
-    }
-    new Kandan.Collections.ActiveUsers().fetch {
-      success: @onFetchActiveUsers(initializer)
-    }
-    new Kandan.Collections.Users().fetch {
-      success: @onFetchUsers(initializer)
-    }
+    # Call the asynchronous initializers, passing the synchronous
+    # initializer in as the callback to execute after all asynchrnous
+    # initialization is complete.
+    _(asyncInitializers).each (f) -> f.call(@, syncInitializer)
+
+    # The following intiialization routines don't require deferred
+    # initialization and can be executed immediately.
     @registerUtilityEvents()
     @initBroadcasterAndSubscribe()
+    @registerAppEvents()
 
-  createCallback: (limit, callback)->
+  # Create a function that is fired only after it has been attempted
+  # `limit` times.
+  callAfter: (limit, callback) ->
     finishedCalls = 0
     -> callback() if ++finishedCalls == limit
-
-  onFetchChannels: (callback) ->
-    (channels) =>
-      Kandan.Helpers.Channels.setCollection(channels)
-      callback()

      Kandan.Helpers.Utils.browserTabFocused = false
    )


  initBroadcasterAndSubscribe: ()->
    Kandan.broadcaster = eval "new Kandan.Broadcasters.#{@options().broadcaster.name}Broadcaster()"
    Kandan.broadcaster.subscribe "/channels/*"
    @registerAppEvents()

  initTabs: ()->
    $('#kandan').tabs({

    chatArea = new Kandan.Views.ChatArea({channels: channels})
    $(".main-area").append(chatArea.render().el)

  onFetchChannels: (callback) ->
    (channels) ->
      Kandan.Helpers.Channels.setCollection(channels)
      callback()

  onFetchActiveUsers: (callback) ->
    (activeUsers) ->
      if not Kandan.Helpers.ActiveUsers.collectionHasCurrentUser(activeUsers)
        activeUsers.add([Kandan.Helpers.Users.currentUser()])
      Kandan.Helpers.ActiveUsers.setFromCollection(activeUsers)
      callback()

  onFetchUsers: (callback) ->
    (users) ->
      Kandan.Helpers.Users.setFromCollection(users)
      callback()

  registerUtilityEvents: ()->
