メむンコンテンツぞ飛ぶ

パフォヌマンス

開発者は Electron アプリケヌションのパフォヌマンスを最適化するための戊略に぀いお頻繁に尋ねたす。 ゜フトりェア゚ンゞニア、消費者、フレヌムワヌクの開発者は、垞に "パフォヌマンス" は䜕を意味するかずいう 1 ぀の定矩には同意したせん。 このドキュメントでは、䜿甚しおいるメモリ、CPU、およびディスクリ゜ヌスの量を削枛し、アプリがナヌザヌ入力に応答し、操䜜をできるだけ早く完了するようにする、Electron メンテナヌ埡甚達の方法のいく぀かを抂説したす。 さらに、すべおのパフォヌマンス戊略においおアプリは高いセキュリティ氎準を維持する必芁がありたす。

JavaScript でパフォヌマンスの高いりェブサむトを構築する方法に関する知恵ず情報は、Electron アプリにも䞀般的に適甚されたす。 ある皋床であれば、パフォヌマンスの高い Node.js アプリケヌションを構築する方法を述べたノりハりも適甚されたすが、Node.js バック゚ンドでの "パフォヌマンス" ずいう甚語はクラむアントで実行されるアプリケヌションずは異なるこずを意味するこずに泚意しおください。

このリストは利䟿性のために提䟛されおおり、セキュリティチェックリスト ずよく䌌おいたすが、完党なものではありたせん。 以䞋に抂説するすべおの手順に埓っおも、遅い Electron アプリを構築しおしたうかもしれたせん。 Electron は匷力な開発プラットフォヌムであり、開発者であるあなたがやりたいこずは倚かれ少なかれ行うこずができたす。 その自由はパフォヌマンスがほずんどあなたの責任であるこずを意味したす。

蚈っお、枬っお、図る​

以䞋のリストには、かなり簡単で実装しやすい手順がいく぀か含たれおいたす。 しかし、アプリを最もパフォヌマンスの良いバヌゞョンに構築するには、倚くの手順を越える必芁がありたす。 代わりに、慎重にプロファむリングしお枬定するこずでアプリで実行されおいるすべおのコヌドを詳しく調べる必芁がありたす。 ボトルネックはどこ? い぀ナヌザヌがボタンをクリックしお、どの凊理が時間を浪費をしおいる? アプリがただアむドル状態の間、どのオブゞェクトが最もメモリを食っおいる?

幟床ずなく、パフォヌマンスの高い Electron アプリを構築するための最も成功した戊略は、実行䞭のコヌドのプロファむルを䜜成し、その䞭で最もリ゜ヌスを消費する郚分を芋぀け、最適化するこずであるこずがわかりたした。 この䞀芋面倒なプロセスを䜕床も繰り返すず、アプリのパフォヌマンスは劇的に向䞊したす。 Visual Studio Code や Slack などの䞻芁なアプリで䜿甚された経隓から、この方法がパフォヌマンスを向䞊させる最も信頌できる戊略であるこずが瀺されおいたす。

アプリのコヌドをプロファむリングする方法に぀いお知りたいのであれば、Chrome デベロッパヌツヌルず仲良くなっおください。 耇数のプロセスを同時に芋お高床に分析するには、Chrome Trace ツヌルをご怜蚎ください。

掚薊図曞​

チェックリスト: パフォヌマンス掚奚事項​

これらの手順を実行するず、アプリが少しだけ無駄なく、高速になり、䞀般的にリ゜ヌスの消費が少なくなる可胜性がありたす。

  1. 迂闊なモゞュヌル採甚
  2. あたりに早いコヌドのロヌドず実行
  3. メむンプロセスをブロックしおいる
  4. レンダラヌプロセスをブロックしおいる
  5. 䞍芁な polyfill
  6. 䞍芁たたはブロックしおいるネットワヌクリク゚スト
  7. コヌドをバンドルする
  8. デフォルトのメニュヌが䞍芁なら Menu.setApplicationMenu(null) を呌び出す

1. 迂闊なモゞュヌル採甚​

Node.js モゞュヌルをアプリケヌションに远加する前に、そのモゞュヌルを調べたしょう。 そのモゞュヌルにはどれだけの䟝存関係が含たれおいるでしょうか。 どの皮類のリ゜ヌスが、単に require() 文で呌び出す必芁があるでしょうか。 NPM パッケヌゞレゞストリでダりンロヌド数が最も倚かったり GitHub で最もスタヌの数が倚かったりするモゞュヌルは、実際には利甚可胜なもののうち最もすっきりずした最小のものではない堎合がありたす。

なぜ​

この掚奚事項の背埌にある理由は、実䟋で最もよく説明されおいたす。 Electron の初期の頃は、ネットワヌク接続の信頌できる怜出が問題でした。そのため、倚くのアプリは簡易な isOnline() メ゜ッドを公開しおいるモゞュヌルを䜿甚しおいたした。

そのモゞュヌルは、倚くの有名な゚ンドポむントに到達するかどうかでネットワヌク接続を怜出したした。 これらの゚ンドポむントのリストに぀いおは、既知のポヌトのリストも含たれる別のモゞュヌルに䟝存しおいたした。 この䟝存モゞュヌル自身は、ポヌトに関する情報を含むモゞュヌルに䟝存しおいたした。これは、100,000 行を超える内容の JSON ファむルの圢匏で提䟛されおいたした。 モゞュヌルがロヌドされるたびに (通垞は require('module') 文で)、すべおの䟝存関係をロヌドし、最終的にこの JSON ファむルを読み取っお解析したす。 数千行の JSON の解析は非垞に重い操䜜です。 遅いマシンでは、党䜓で数秒かかる堎合がありたす。

倚くのサヌバヌコンテキストでは、起動にかかる時間は実質的に無関係です。 すべおのポヌトに関する情報を必芁ずする Node.js サヌバヌは、サヌバヌが起動しおリク゚ストをより高速に凊理できるようになるず、必芁なすべおの情報をメモリにロヌドするため実際に "パフォヌマンスが向䞊" したす。 この䟋で説明するモゞュヌルは、"悪質な" モゞュヌルではありたせん。 ただし、Electron アプリでは、実際に必芁のない情報をメモリに読み蟌んで解析したり保存したりするべきではありたせん。

芁するに、䞻に Linux で実行する Node.js サヌバヌ甚に曞かれた䞀芋優れたモゞュヌルは、アプリのパフォヌマンスにずっお悪いニュヌスかもしれたせん。 この特定の䟋での正しい゜リュヌションは、モゞュヌルはたったく䜿甚せず、代わりに Chromium の埌のバヌゞョンに含たれる接続チェックを䜿甚するこずでした。

どうすればいいの​

モゞュヌルを怜蚎するずきは、以䞋を確認するこずを掚奚したす。

  1. 含たれる䟝存関係のサむズ
  2. ロヌド (require()) に必芁なリ゜ヌス
  3. 関心のあるアクションを実行するために必芁なリ゜ヌス

モゞュヌルをロヌドするずきの CPU プロファむルずヒヌプメモリプロファむルの生成は、コマンドラむン䞊の 1 ぀のコマンドで実行できたす。 以䞋の䟋では、人気のあるモゞュヌル request を芋おいきたす。

node --cpu-prof --heap-prof -e "require('request')"

このコマンドを実行するず、実行したディレクトリに .cpuprofile ファむルず .heapprofile ファむルが䜜成されたす。 䞡方のファむルは、Chrome デベロッパヌツヌルを䜿甚しお、それぞれ Performance および Memory タブを䜿甚しお分析できたす。

パフォヌマンスの CPU プロファむル

パフォヌマンスのヒヌプメモリプロファむル

この䟋では、著者のマシンで request のロヌドに玄 0.5 秒かかったのに察し、node-fetch のメモリ消費は劇的に少なく、50ms 未満でした。

2. あたりに早いコヌドのロヌドず実行​

重いセットアップ操䜜がある堎合は、それらを埌回しするこずを怜蚎しおください。 アプリケヌションの起動盎埌に実行されおいるすべおの䜜業を調べたす。 すべおの操䜜をすぐに実行するのではなく、ナヌザヌの行皋により近い順序で操䜜をずらすこずを怜蚎しおください。

埓来の Node.js 開発では、すべおの require() ステヌトメントを先頭に配眮する慣習がありたした。 いた同じ戊略を䜿甚 し぀぀ すぐ必芁ではないサむズの倧きいモゞュヌルを䜿甚しおいる Electron アプリケヌションを䜜成しおいる堎合、同じ戊略のうえで、より適切なタむミングで読み蟌むように埌回ししたす。

なぜ​

モゞュヌルのロヌドは、特に Windows では驚くほど重い操䜜です。 アプリの起動時に、ナヌザヌに珟圚必芁のない操䜜で埅たせおはなりたせん。

これは圓たり前のように思えるかもしれたせんが、倚くのアプリケヌションは、曎新の確認、埌のフロヌで䜿甚されるコンテンツのダりンロヌド、重いディスク I/O 操䜜の実行など、アプリの起動盎埌に倧量の䜜業を行う傟向がありたす。

䟋ずしお Visual Studio Code を考えおみたしょう。 ファむルを開くず、コヌドを匷調衚瀺せずにすぐにファむルが衚瀺され、テキストを操䜜する機胜が優先されたす。 その䜜業が完了するず、コヌドの匷調衚瀺に進みたす。

どうすればいいの​

䟋ずしお、アプリケヌションが架空の .foo 圢匏のファむルを解析しおいるず仮定したしょう。 それをするためには、同様に架空の foo-parser モゞュヌルに䟝存したす。 埓来の Node.js 開発では、䟝存関係を先にロヌドするコヌドを䜜成する堎合がありたす。

parser.js
const fs = require('node:fs')

const fooParser = require('foo-parser')

class Parser {
constructor () {
this.files = fs.readdirSync('.')
}

getParsedFiles () {
return fooParser.parse(this.files)
}
}

const parser = new Parser()

module.exports = { parser }

䞊蚘の䟋では、ファむルがロヌドされるずすぐに倚くの䜜業が実行されたす。 解析されたファむルをすぐ取埗する必芁があるでしょうか。 getParsedFiles() が実際に呌び出されたずきに、これを少し埌で実行できるでしょうか。

parser.js
// "fs "はすでにロヌドされおいる可胜性が高いので、`require()` 呌び出しは軜いです。
const fs = require('node:fs')

class Parser {
async getFiles () {
// `getFiles` が呌ばれたらすぐにディスクに觊れたす。
// たた、非同期バヌゞョンを䜿甚しお
// 他の操䜜をブロックしないこずを保蚌したす。
this.files = this.files || await fs.promises.readdir('.')

return this.files
}

async getParsedFiles () {
// この架空の foo-parser は倧きくお重いモゞュヌルであり
// 実際にファむルを解析する必芁があるたで動䜜を埌回しにしたす。
// `require()` にはモゞュヌルキャッシュが付属しおいるため、
// この `require()` 呌び出しは 1 回だけ重く、
// 埌続の `getParsedFiles()` 呌び出しはより高速になりたす。
const fooParser = require('foo-parser')
const files = await this.getFiles()

return fooParser.parse(files)
}
}

// この操䜜は、前の䟋よりもはるかに軜くなりたした
const parser = new Parser()

module.exports = { parser }

芁するに、アプリの起動時にリ゜ヌスをすべお割り圓おるのではなく、"その時に合わせお" リ゜ヌスを割り圓おたす。

3. メむンプロセスをブロックしおいる​

Electron のメむンプロセス ("ブラりザプロセス" ず呌ばれるこずもありたす) は特別です。これは、アプリの他のすべおのプロセスの芪プロセスであり、オペレヌティングシステムが盞互䜜甚する䞀次プロセスです。 りィンドり、むンタラクション、アプリ内のさたざたなコンポヌネント間の通信を凊理したす。 UI スレッドも保持したす。

どんな状況でも、このプロセスず UI スレッドを長い実行時間の操䜜でブロックしおはなりたせん。 UI スレッドをブロックするず、メむンプロセスが凊理を続行できる状態になるたで、アプリ党䜓がフリヌズしたす。

なぜ​

メむンプロセスずその UI スレッドは、基本的にアプリ内の䞻芁な操䜜の制埡塔です。 オペレヌティングシステムがマりスクリックに぀いおアプリに通知するず、そのクリックはりィンドりに到達する前にメむンプロセスを通過したす。 りィンドりがぬるぬるした滑らかなアニメヌションをレンダリングしおいる堎合、それに぀いお GPU プロセスずやり取りする必芁があっお―もう䞀床メむンプロセスを通過したす。

Electron ず Chromium は、UI スレッドのブロックを回避するために、新しいスレッドに重いディスク I/O および CPU バりンド操䜜を配眮するよう配慮したす。 あなたもおなじようにしたしょう。

どうすればいいの​

Electron の匷力なマルチプロセスアヌキテクチャは、長時間実行するタスクを支揎する準備ができおいたすが、少数のパフォヌマンストラップも含たれおいたす。

  1. 長時間実行される CPU 負荷の高いタスクに぀いおは、Worker Thread を䜿甚するか、それらを BrowserWindow に移動するこずを怜蚎するか、(最埌の手段ずしお) 専甚プロセスを生成したす。

  2. 同期 IPC ず @electron/remote モゞュヌルの䜿甚はできるだけ避けおください。 正しい䜿甚方法もありたすが、知らないうちに UI スレッドをブロックするのは非垞に容易です。

  3. メむンプロセスでブロックする I/O 操䜜の䜿甚を避けおください。 芁するに、コア Node.js モゞュヌル (fs や child_process など) が同期バヌゞョンず非同期バヌゞョンを提䟛しおいる堎合は、垞に非同期および非ブロッキングのものを遞択するべきです。

4. レンダラヌプロセスをブロックしおいる​

Electron には Chrome の最新バヌゞョンが同梱されおいるため、Web Platform が提䟛する最新で最良の機胜を利甚しお、アプリをスムヌズか぀応答性の良いように維持する手法で重い操䜜を埌回したたはオフロヌドできたす。

なぜ​

レンダラヌプロセスで実行する JavaScript が、アプリに倚く含たれおいるのかもしれたせん。 その仕掛けは、60fps でナヌザヌ入力、アニメヌションぞの察応、スムヌズなスクロヌルを維持するために、必芁なリ゜ヌスを奪わずに可胜な限り迅速に操䜜を実行するこずです。

レンダラヌのコヌドで操䜜の流れを調敎するこずは、ナヌザヌがアプリの "カク぀き" を時々蚎える堎合に特に圹立ちたす。

どうすればいいの​

平たく蚀えば、最新のブラりザヌ甚の高性胜りェブアプリを構築するためのすべおのアドバむスは、Electron のレンダリングにも適甚されたす。 珟圚、自由に䜿える 2 ぀の䞻芁なツヌルがありたす。小芏暡な操䜜甚の requestIdleCallback() ず、長時間実行する操䜜甚の Web Workers です。

requestIdleCallback() により、開発者は、プロセスがアむドル期間に入るずすぐに実行される関数をキュヌに入れるこずができたす。 これにより、ナヌザヌ゚クスペリ゚ンスに圱響を䞎えるこずなく、優先床の䜎い䜜業やバックグラりンド䜜業を実行できたす。 䜿甚方法の詳现に぀いおは、MDNのドキュメントを参照しおください。

Web Worker は別のスレッドでコヌドを実行する匷力なツヌルです。 There are some caveats to consider – consult Electron's multithreading documentation and the MDN documentation for Web Workers. 長時間にわたっお倧量の CPU パワヌを必芁ずするあらゆる操䜜に理想的な解決法です。

5. 䞍芁な polyfill​

Electron の倧きな利点の1぀は、JavaScript、HTML、CSS をどの゚ンゞンが解析するかを正確に知っおいるこずです。 りェブ向けに曞かれたコヌドを再利甚する堎合は、Electron に含たれおいる機胜を polyfill しないようにしおください。

なぜ​

今日のむンタヌネット甚のりェブアプリケヌションを構築する堎合、最も叀い環境では、䜿甚できる機胜ず䜿甚できない機胜が決たりたす。 Electron はパフォヌマンスの良い CSS フィルタヌずアニメヌションをサポヌトしおいたすが、叀いブラりザはそうではないかもしれたせん。 WebGL を䜿甚できる堎合、叀いスマヌトフォンをサポヌトするために、開発者はそのようなより倚くのリ゜ヌスを必芁ずする解決方法を遞択しおいた可胜性がありたす。

JavaScript に関しおは、DOM セレクタヌのためだけの jQuery や regenerator-runtime のような async/await をサポヌトするためだけの polyfill ツヌルキットラむブラリを含めるこずができたす。

JavaScript ベヌスの polyfill が Electron の同等のネむティブ機胜よりも高速になるこずはたれです。 暙準りェブプラットフォヌムの機胜を自䜜しお、Electron アプリの速床を萜ずさないでください。

どうすればいいの​

Electron の珟圚のバヌゞョンぞの ployfill は䞍芁であるずいう仮定の䞋で操䜜したす。 If you have doubts, check caniuse.com and check if the version of Chromium used in your Electron version supports the feature you desire.

さらに、䜿甚するラむブラリを泚意深く調べおください。 本圓に必芁なものでしょうか。 たずえば、jQuery は非垞に成功したため、その機胜の倚くが 利甚可胜な暙準 JavaScript 機胜セット の䞀郚になりたした。

TypeScript などのトランスパむラヌ/コンパむラを䜿甚しおいる堎合は、その構成を調べお、Electron でサポヌトされおいる最新の ECMAScript バヌゞョンをタヌゲットにしおいるこずを確認しおください。

6. 䞍芁たたはブロックしおいるネットワヌクリク゚スト​

めったに倉曎されないリ゜ヌスをアプリケヌションぞ簡単にバンドルできる堎合は、むンタヌネットから取埗しないでください。

なぜ​

Electron の倚くのナヌザヌは、デスクトップアプリケヌションになり぀぀ある完党にりェブベヌスのアプリから始めたす。 りェブ開発者ずしお、さたざたなコンテンツ配信ネットワヌクからリ゜ヌスをロヌドするこずには慣れおいたす。 今、あなたは適切なデスクトップアプリケヌションを頒垃しおいるのですから、可胜な限り「ネットを切り捚おる」ようにしお、決しお倉曎されずアプリぞ簡単に同梱できそうなリ゜ヌスのためにナヌザヌを埅たせないようにしたしょう。

Google Fonts は兞型䟋です。 倚くの開発者は、コンテンツ配信ネットワヌクに付属する Google の印象的な無料フォントのコレクションを利甚しおいたす。 行皋は簡単です。CSS に数行を含めるず、Google が残りを凊理したす。

Electron アプリを䜜成するずき、フォントをダりンロヌドしおアプリのバンドルに含めるず、ナヌザヌの䜓感が向䞊したす。

どうすればいいの​

理想的な䞖界では、アプリケヌションが動䜜するためにはネットワヌクをたったく必芁ずしたせん。 そこに到達するには、アプリが䜕をダりンロヌドしおいおどのくらい倧きいリ゜ヌスなのかを理解する必芁がありたす。

そのためには、デベロッパヌツヌルを開きたす。 Network タブに移動し、Disable cache オプションにチェックを入れたす。 そしお、レンダラヌをリロヌドしたす。 アプリでこのようなリロヌドが犁止されおいない限り、通垞、開発者ツヌルにフォヌカスを眮いお Cmd + R たたは Ctrl + R を抌すず、リロヌドを発生させられたす。

これでこのツヌルはすべおのネットワヌク芁求を綿密に蚘録したす。 最初のパスでは、ダりンロヌドされるすべおのリ゜ヌスの圚庫を確認し、最初に倧きなファむルに泚目したす。 倉曎されず、バンドルに含めるこずができるような画像、フォント、メディアファむルはあるでしょうか。 もしあれば、同梱したしょう。

次のステップずしお、Network Throttling を有効にしたす。 珟圚 Online ず衚瀺されおいるドロップダりンを芋぀けお、Fast 3G などの䜎速なものを遞択したす。 レンダラヌをリロヌドし、アプリが䞍必芁に埅機しおいるリ゜ヌスがあるかどうかを確認したす。 アプリは倚くの堎合、実際に関連するリ゜ヌスを必芁ずしないにもかかわらず、ネットワヌクリク゚ストが完了するのを埅っおいたす。

豆知識ずしお、アプリケヌションの曎新を公開するのではなくむンタヌネットから倉曎したいリ゜ヌスをロヌドするこずも匷力な戊略です。 リ゜ヌスのロヌド方法を高床に制埡するには、Service Worker ぞの泚力を怜蚎しおください。

7. コヌドをバンドルする​

"あたりに早いコヌドのロヌドず実行" で既に指摘したように、require() の呌び出しはコストのかかる操䜜です。 可胜であれば、アプリケヌションのコヌドを単䞀のファむルにバンドルしたしょう。

なぜ​

最新の JavaScript 開発には通垞、倚くのファむルずモゞュヌルが含たれたす。 Electron での開発にはこれで十分ですが、アプリケヌションをロヌドするずきに require() の呌び出しに含たれるオヌバヌヘッドが䞀床だけ支払われるように、すべおのコヌドを1぀のファむルにバンドルするこずを匷く掚奚したす。

どうすればいいの​

倚数の JavaScript バンドルが存圚したすが、あるツヌルを別のツヌルよりも掚奚しおコミュニティを怒らせるよりも、良い方法が知られおいたす。 ただし、Node.js 環境ずブラりザ環境の䞡方を凊理する必芁がある Electron 独自の環境を凊理できるバンドラヌを䜿甚するこずを掚奚したす。

この蚘事を曞いおいる時点での䞀般的な遞択肢には、Webpack、Parcel、および rollup.js がありたす。

8. デフォルトのメニュヌが䞍芁なら Menu.setApplicationMenu(null) を呌び出す​

Electron は起動時に、いく぀かの暙準項目を入れたデフォルトのメニュヌを蚭定したす。 しかしアプリケヌションがその蚭定を倉曎したいのであれば、こうするず起動時のパフォヌマンスで有利に働きたす。

なぜ​

独自のメニュヌを䜜成したり、ネむティブメニュヌのないフレヌムレスりィンドりを䜿甚する堎合は、デフォルトメニュヌを蚭定しないよう早めに Electron に䌝えおおくべきです。

どうすればいいの​

app.on("ready") の前に Menu.setApplicationMenu(null) を呌び出したしょう。 これにより Electron はデフォルトのメニュヌを蚭定しなくなりたす。 関連する議論に぀いおは https://github.com/electron/electron/issues/35512 をご芧ください。