From fcae064dbba51efeeb67bd53730979c1dc23b970 Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Sat, 1 Oct 2016 01:09:51 -0700 Subject: [PATCH] perf: ~40ms improvement: Lazy load controllers and page components --- package.json | 1 + src/crash-reporter.js | 6 +- src/main/windows/main.js | 2 +- src/main/windows/webtorrent.js | 2 - src/renderer/lib/errors.js | 5 +- src/renderer/main.js | 142 +++++++++++++----------- src/renderer/pages/app.js | 33 ++++-- src/renderer/pages/torrent-list-page.js | 3 +- 8 files changed, 107 insertions(+), 87 deletions(-) diff --git a/package.json b/package.json index 4625e62f..8e3107df 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "drag-drop": "^2.12.1", "electron": "1.4.2", "es6-error": "^3.0.1", + "fn-getter": "^1.0.0", "iso-639-1": "^1.2.1", "languagedetect": "^1.1.1", "location-history": "^1.0.0", diff --git a/src/crash-reporter.js b/src/crash-reporter.js index 44e4377c..8fd2ac15 100644 --- a/src/crash-reporter.js +++ b/src/crash-reporter.js @@ -2,10 +2,10 @@ module.exports = { init } -const config = require('./config') -const electron = require('electron') - function init () { + const config = require('./config') + const electron = require('electron') + electron.crashReporter.start({ companyName: config.APP_NAME, productName: config.APP_NAME, diff --git a/src/main/windows/main.js b/src/main/windows/main.js index 0cd82636..44e9f9c4 100644 --- a/src/main/windows/main.js +++ b/src/main/windows/main.js @@ -112,7 +112,7 @@ function dispatch (...args) { function hide () { if (!main.win) return - main.win.send('dispatch', 'backToList') + dispatch('backToList') main.win.hide() } diff --git a/src/main/windows/webtorrent.js b/src/main/windows/webtorrent.js index e50896a3..a524c686 100644 --- a/src/main/windows/webtorrent.js +++ b/src/main/windows/webtorrent.js @@ -9,7 +9,6 @@ const webtorrent = module.exports = { const electron = require('electron') const config = require('../../config') -const log = require('../log') function init () { const win = webtorrent.win = new electron.BrowserWindow({ @@ -52,7 +51,6 @@ function send (...args) { function toggleDevTools () { if (!webtorrent.win) return - log('toggleDevTools') if (webtorrent.win.webContents.isDevToolsOpened()) { webtorrent.win.webContents.closeDevTools() webtorrent.win.hide() diff --git a/src/renderer/lib/errors.js b/src/renderer/lib/errors.js index 80ca2688..4540c8c2 100644 --- a/src/renderer/lib/errors.js +++ b/src/renderer/lib/errors.js @@ -29,8 +29,6 @@ class TorrentKeyNotFoundError extends TorrentError { constructor (torrentKey) { super(`Can't resolve torrent key ${torrentKey}`) } } -class InvalidTorrentError extends TorrentError {} - module.exports = { CastingError, PlaybackError, @@ -39,6 +37,5 @@ module.exports = { UnplayableTorrentError, UnplayableFileError, InvalidSoundNameError, - TorrentKeyNotFoundError, - InvalidTorrentError + TorrentKeyNotFoundError } diff --git a/src/renderer/main.js b/src/renderer/main.js index 1687c85b..ec7b6bf7 100644 --- a/src/renderer/main.js +++ b/src/renderer/main.js @@ -28,6 +28,7 @@ crashReporter.init() const State = require('./lib/state') State.load(onState) +const createGetter = require('fn-getter') const dragDrop = require('drag-drop') const electron = require('electron') const fs = require('fs') @@ -39,19 +40,13 @@ const telemetry = require('./lib/telemetry') const sound = require('./lib/sound') const TorrentPlayer = require('./lib/torrent-player') +const TorrentListController = require('./controllers/torrent-list-controller') + // Required by Material UI -- adds `onTouchTap` event require('react-tap-event-plugin')() const App = require('./pages/app') -const MediaController = require('./controllers/media-controller') -const UpdateController = require('./controllers/update-controller') -const PrefsController = require('./controllers/prefs-controller') -const PlaybackController = require('./controllers/playback-controller') -const SubtitlesController = require('./controllers/subtitles-controller') -const TorrentListController = require('./controllers/torrent-list-controller') -const TorrentController = require('./controllers/torrent-controller') - // Electron apps have two processes: a main process (node) runs first and starts // a renderer process (essentially a Chrome window). We're in the renderer process, // and this IPC channel receives from and sends messages to the main process @@ -93,13 +88,33 @@ function onState (err, _state) { // Create controllers controllers = { - media: new MediaController(state), - update: new UpdateController(state), - prefs: new PrefsController(state, config), - playback: new PlaybackController(state, config, update), - subtitles: new SubtitlesController(state), - torrentList: new TorrentListController(state), - torrent: new TorrentController(state) + media: createGetter(() => { + const MediaController = require('./controllers/media-controller') + return new MediaController(state) + }), + playback: createGetter(() => { + const PlaybackController = require('./controllers/playback-controller') + return new PlaybackController(state, config, update) + }), + prefs: createGetter(() => { + const PrefsController = require('./controllers/prefs-controller') + return new PrefsController(state, config) + }), + subtitles: createGetter(() => { + const SubtitlesController = require('./controllers/subtitles-controller') + return new SubtitlesController(state) + }), + torrent: createGetter(() => { + const TorrentController = require('./controllers/torrent-controller') + return new TorrentController(state) + }), + torrentList: createGetter(() => { + return new TorrentListController(state) + }), + update: createGetter(() => { + const UpdateController = require('./controllers/update-controller') + return new UpdateController(state) + }) } // Add first page to location history @@ -182,7 +197,7 @@ function lazyLoadCast () { // 3. dispatch - the event handler calls dispatch(), main.js sends it to a controller // 4. controller - the controller handles the event, changing the state object function update () { - controllers.playback.showOrHidePlayerControls() + controllers.playback().showOrHidePlayerControls() app.setState(state) updateElectron() } @@ -210,54 +225,54 @@ const dispatchHandlers = { 'openFiles': () => ipcRenderer.send('openFiles'), /* shows the open file dialog */ 'openTorrentAddress': () => { state.modal = { id: 'open-torrent-address-modal' } }, - 'addTorrent': (torrentId) => controllers.torrentList.addTorrent(torrentId), - 'showCreateTorrent': (paths) => controllers.torrentList.showCreateTorrent(paths), - 'createTorrent': (options) => controllers.torrentList.createTorrent(options), - 'toggleTorrent': (infoHash) => controllers.torrentList.toggleTorrent(infoHash), + 'addTorrent': (torrentId) => controllers.torrentList().addTorrent(torrentId), + 'showCreateTorrent': (paths) => controllers.torrentList().showCreateTorrent(paths), + 'createTorrent': (options) => controllers.torrentList().createTorrent(options), + 'toggleTorrent': (infoHash) => controllers.torrentList().toggleTorrent(infoHash), 'toggleTorrentFile': (infoHash, index) => - controllers.torrentList.toggleTorrentFile(infoHash, index), + controllers.torrentList().toggleTorrentFile(infoHash, index), 'confirmDeleteTorrent': (infoHash, deleteData) => - controllers.torrentList.confirmDeleteTorrent(infoHash, deleteData), + controllers.torrentList().confirmDeleteTorrent(infoHash, deleteData), 'deleteTorrent': (infoHash, deleteData) => - controllers.torrentList.deleteTorrent(infoHash, deleteData), + controllers.torrentList().deleteTorrent(infoHash, deleteData), 'toggleSelectTorrent': (infoHash) => - controllers.torrentList.toggleSelectTorrent(infoHash), + controllers.torrentList().toggleSelectTorrent(infoHash), 'openTorrentContextMenu': (infoHash) => - controllers.torrentList.openTorrentContextMenu(infoHash), + controllers.torrentList().openTorrentContextMenu(infoHash), 'startTorrentingSummary': (torrentKey) => - controllers.torrentList.startTorrentingSummary(torrentKey), + controllers.torrentList().startTorrentingSummary(torrentKey), 'saveTorrentFileAs': (torrentKey) => - controllers.torrentList.saveTorrentFileAs(torrentKey), + controllers.torrentList().saveTorrentFileAs(torrentKey), // Playback - 'playFile': (infoHash, index) => controllers.playback.playFile(infoHash, index), - 'playPause': () => controllers.playback.playPause(), - 'nextTrack': () => controllers.playback.nextTrack(), - 'previousTrack': () => controllers.playback.previousTrack(), - 'skip': (time) => controllers.playback.skip(time), - 'skipTo': (time) => controllers.playback.skipTo(time), - 'changePlaybackRate': (dir) => controllers.playback.changePlaybackRate(dir), - 'changeVolume': (delta) => controllers.playback.changeVolume(delta), - 'setVolume': (vol) => controllers.playback.setVolume(vol), - 'openItem': (infoHash, index) => controllers.playback.openItem(infoHash, index), + 'playFile': (infoHash, index) => controllers.playback().playFile(infoHash, index), + 'playPause': () => controllers.playback().playPause(), + 'nextTrack': () => controllers.playback().nextTrack(), + 'previousTrack': () => controllers.playback().previousTrack(), + 'skip': (time) => controllers.playback().skip(time), + 'skipTo': (time) => controllers.playback().skipTo(time), + 'changePlaybackRate': (dir) => controllers.playback().changePlaybackRate(dir), + 'changeVolume': (delta) => controllers.playback().changeVolume(delta), + 'setVolume': (vol) => controllers.playback().setVolume(vol), + 'openItem': (infoHash, index) => controllers.playback().openItem(infoHash, index), // Subtitles - 'openSubtitles': () => controllers.subtitles.openSubtitles(), - 'selectSubtitle': (index) => controllers.subtitles.selectSubtitle(index), - 'toggleSubtitlesMenu': () => controllers.subtitles.toggleSubtitlesMenu(), - 'checkForSubtitles': () => controllers.subtitles.checkForSubtitles(), - 'addSubtitles': (files, autoSelect) => controllers.subtitles.addSubtitles(files, autoSelect), + 'openSubtitles': () => controllers.subtitles().openSubtitles(), + 'selectSubtitle': (index) => controllers.subtitles().selectSubtitle(index), + 'toggleSubtitlesMenu': () => controllers.subtitles().toggleSubtitlesMenu(), + 'checkForSubtitles': () => controllers.subtitles().checkForSubtitles(), + 'addSubtitles': (files, autoSelect) => controllers.subtitles().addSubtitles(files, autoSelect), // Local media: