atom / github

:octocat: Git and GitHub integration for Atom
https://github.atom.io
MIT License
1.12k stars 393 forks source link

Defer loading of parts of the GitHub package to shorten startup time #1522

Open daviwil opened 6 years ago

daviwil commented 6 years ago

Hey folks! I was chatting with @smashwilson about this idea and he suggested I file an issue to track it.

I'd love to be able to implement the Updatable Bundled Packages RFC so that the GitHub package can release updates independently even though it's a bundled package. The one remaining concern I have is that the load time for the GitHub package increases from ~50ms to ~500ms when it's no longer loaded as part of Atom's V8 snapshot. Since it isn't currently possible to snapshot user-installed packages, we would need to find another way to make up for the load time increase since it will likely be perceptible at this scale.

One possible mitigation is for the GitHub package to lazily load its functionality so the loading cost is spread out more evenly as Atom starts up and becomes ready. Right now it seems that everything gets loaded up right at startup; what I'm imagining is something like this:

  1. GitHub package gets loaded at startup but only requires the minimal code necessary to get going
  2. Package activation hooks into the atom.whenShellEnvironmentLoaded event and waits for that before loading more of its core components (React and Redux maybe?)
  3. Some of the UI elements could be lazily loaded on demand. For instance, the GitHub tab could be required just as it as requested

One problem I can imagine for this right now is that our snapshotting process currently requires that as much package code be loaded into the JavaScript heap as possible so that it will be included. The GitHub package may need to become aware of whether it's being loaded as part of snapshot generation so that it can optimistically load more of its code.

daviwil commented 6 years ago

Another possibility for step 2, thanks to @Arcanemagus: use window.requestIdleCallback to have some additional loading behavior occur once the JavaScript thread goes idle:

const makeIdleCallback = (work) => {
  let callbackId
  const callBack = () => {
    idleCallbacks.delete(callbackId)
    work()
  }
  callbackId = window.requestIdleCallback(callBack)
  idleCallbacks.add(callbackId)
}

Source: https://github.com/AtomLinter/linter-eslint/blob/master/src/main.js#L34-L59