Package activation time impacted heavily by configuration


I’m having a lot of fun packing a bunch of config option into my Isotope UI theme, but I am noticing this comes at a price. If I take my coffee file out it will usually not show up in Timecop (< 5 ms), but with the coffee it takes around 60ms. I don’t think I’m doing anything exotic other than some @font-face stuff but that doesn’t seem to impact anything much (as the @font-face is there without the config). Of course 60ms isn’t massive, but it’s quite high in Timecop and I’m worried adding more configuration will slow things down.

My coffee file is here:

Basically it defines a bunch of config options, functions to be run to apply the config, and then runs them on atom.workspaceView.ready and again for each config.onDidChange.

Any tips on getting the activation time down a few notches?


Well, I doubt that it is the config itself that is taking up all the time on activation, but the code in the activate method. What you could do is take all of that code and place it in a separate module and load it in the atom.workspaceView.ready handler. So your activate would look like this:

activate: ->
  atom.workspaceView.ready ->
    Config = require './config'

That would defer even the CoffeeScript compilation until the ready event, if my understanding is correct. And it should get you back off of TimeCop’s radar.


Oh, great, thanks! Figured there must be a trick like that in there somewhere :sunglasses:


I’ve wondered whether these delaying tactics actually help the user experience. The atom/atom issue with a subject line like “Boom! Loading is fast” announces a package that delays almost everything. I’ve thought that putting all my code in a big timeout would get me past the “radar”.

It would seem to me that you can’t get a speed up with delays. Don’t you have to pay the piper at some point>


Yes, you do have to pay the piper at some point. But also, isn’t this what the asynchronous model of Node is all about? Delaying until later what you can so that other things can have their turn because threads are hard and single-threading is the bomb? (There isn’t a sarcasm emoji or I would use it :laughing:)

Besides, the code that I suggested shifting isn’t actually used until the atom.workspaceView.ready event … so why should the activation of other packages be delayed for that?


I was able to significantly bring the number in Timecop down by switching from config.observe to config.onDidChange (50% win), and then some more by following @leedohm’s suggestion (another 30% win). Must be a win in terms over overall window load time, but I’m not sure.

And I don’t really know how this affects user experience in Atom. In websites you can move stuff around to get something on the screen asap, but if you postpone certain things too much your user is still going to sit around waiting for everything to stop moving. As you say, you have to pay the piper anyway and you have to get it over with.

Postponing the application of styles might not be ideal, but I haven’t figured out how to learn how Atom is spending its time. Should I be worried about repaints triggered by config? Anyway, as Lee is saying, only good things for this use case.


I think you can use the profiling capabilities in the Developer Tools and reload the window to maybe capture some of this stuff? I’m not sure. I really should learn more about the profiling stuff in Chromium.


It’s been a while since I last did an audit like that and it must’ve been in Firebug or Safari… The timeline is giving some info, but I going to have to dig in to learn anything from it. If anything it seems to take less time rendering and painting with Minimap than without, so…

Anyway, thanks!


Not actually. Node gets an advantage with callbacks of overlapping IO. Different sync tasks that aren’t IO-bound stack up and require the same time as having all the sync code in one event loop.


@leedohm since atom.workspaceView is now deprecated, what would the replacement for atom.workspaceView.ready ->? I’m not finding anything in the docs (most of that being way over my head)…


I’d probably use atom.packages.onDidActivateInitialPackages.


Just for posterity: atom.themes.onDidChangeActiveThemes is the one I need. It’s called when atom loads and every time a theme changes (so also when a theme is first selected). atom.packages.onDidActivateInitialPackages is not called when a theme is loaded, which makes the theme code not run when it’s first selected.