diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/ja/tools/performance/scenarios | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/ja/tools/performance/scenarios')
3 files changed, 397 insertions, 0 deletions
diff --git a/files/ja/tools/performance/scenarios/animating_css_properties/index.html b/files/ja/tools/performance/scenarios/animating_css_properties/index.html new file mode 100644 index 0000000000..106a08aecc --- /dev/null +++ b/files/ja/tools/performance/scenarios/animating_css_properties/index.html @@ -0,0 +1,156 @@ +--- +title: CSS プロパティのアニメーション +slug: Tools/Performance/Scenarios/Animating_CSS_properties +translation_of: Tools/Performance/Scenarios/Animating_CSS_properties +--- +<div>{{ToolsSidebar}}</div><div class="summary"> +<p>CSS プロパティのアニメーションにかかるパフォーマンスのコストは、プロパティにより異なります。また、高コストな CSS プロパティのアニメーションは、ブラウザがスムーズなフレームレートを確保しようと努力するために <a href="/ja/docs/Glossary/Jank">jank</a> が発生する場合があります。</p> + +<p><a href="/ja/docs/Tools/Performance/Frame_rate">フレームレート</a>や<a href="/ja/docs/Tools/Performance/Waterfall">ウォーターフォール</a>は CSS アニメーションにおいてブラウザが何を行っているかを明らかにして、パフォーマンスの問題の診断を支援します。</p> +</div> + +<p><a href="/ja/docs/Web/Guide/CSS/Using_CSS_animations">CSS アニメーション</a>では複数の<a href="/ja/docs/Web/CSS/@keyframes">キーフレーム</a>を指定して、それぞれのキーフレームではアニメーションの特定の段階における要素の外見を定義するために CSS を使用します。ブラウザは、それぞれのキーフレームから次のキーフレームへ遷移することでアニメーションを作成します。</p> + +<p>JavaScript を使用して要素のアニメーションを行うのに比べて、CSS アニメーションは簡単に作れます。またブラウザはいつフレームを描画するかをより制御でき、また必要に応じてフレームを破棄できますので、パフォーマンスが高くなります。</p> + +<p>しかし CSS プロパティを変更するためのパフォーマンスコストは、プロパティにより異なります。高コストな CSS プロパティのアニメーションは、ブラウザがスムーズなフレームレートを確保しようと努力するために <a href="/ja/docs/Glossary/Jank">jank</a> が発生する場合があります。</p> + +<h2 id="The_CSS_rendering_waterfall" name="The_CSS_rendering_waterfall">CSS レンダリングのウォーターフォール</h2> + +<p>CSS が変更されたときにブラウザがページを更新するためのプロセスは、以下のステップで構成されるウォーターフォールで説明できます:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10821/css-rendering-waterfall.png" style="display: block; height: 203px; margin-left: auto; margin-right: auto; width: 546px;"></p> + +<ol> + <li><strong>スタイルを再計算</strong>: 要素の CSS プロパティが変更されるたびに、ブラウザは算出スタイルを再計算しなければなりません。</li> + <li><strong>レイアウト</strong>: 続いて、要素の位置や形状を計算するために算出スタイルを使用します。この操作は "レイアウト" と名付けられていますが、"リフロー" とも呼ばれます。</li> + <li><strong>描画</strong>: そして、ブラウザはスクリーンに要素を再描画しなければなりません。最後のステップはこの流れで示していません。ページは複数のレイヤーに分割され、それぞれを独立して描画した後に、"コンポジション" と呼ばれるプロセスで合成されます。</li> +</ol> + +<p>この流れが完了しなければスクリーンを更新できませんので、ひとつのフレーム内に一連の操作を収めなければなりません。毎秒 60 フレームが、アニメーションがスムーズに見えるレートとして広く受け入れられています。毎秒 60 フレームのレートのために、ブラウザが一連の操作を実行する時間として 16.7 ミリ秒が与えられます。</p> + +<h2 id="CSS_property_cost" name="CSS_property_cost">CSS プロパティのコスト</h2> + +<p>レンダリングのウォーターフォールにおいて、一部のプロパティは他のプロパティに比べて特にコストが高くなります:</p> + +<table class="fullwidth-table standard-table"> + <thead> + <tr> + <th scope="col">プロパティの種類</th> + <th scope="col">コスト</th> + <th scope="col">例</th> + </tr> + </thead> + <tbody> + <tr> + <td>要素の<em>形状</em>や<em>位置</em>に影響を与えるプロパティ。これらはスタイルの再計算、レイアウト、再描画を発生させる。</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/10827/recalculate-style.png" style="height: 26px; width: 123px;"> <img alt="" src="https://mdn.mozillademos.org/files/10825/layout.png" style="height: 26px; width: 123px;"> <img alt="" src="https://mdn.mozillademos.org/files/10823/paint.png" style="height: 26px; width: 123px;"></td> + <td> + <p><code><a href="/ja/docs/Web/CSS/left">left</a></code><br> + <code><a href="/ja/docs/Web/CSS/max-width">max-width</a></code><br> + <code><a href="/ja/docs/Web/CSS/border-width">border-width</a></code><br> + <code><a href="/ja/docs/Web/CSS/margin-left">margin-left</a></code><br> + <code><a href="/ja/docs/Web/CSS/font-size">font-size</a></code></p> + </td> + </tr> + <tr> + <td> + <p>形状や位置への影響はないが、個別のレイヤーでは描画されないプロパティ。レイアウトは発生しない。</p> + </td> + <td><img alt="" src="https://mdn.mozillademos.org/files/10827/recalculate-style.png" style="height: 26px; width: 123px;"> <img alt="" src="https://mdn.mozillademos.org/files/10835/layout-faint.png" style="height: 52px; width: 123px;"> <img alt="" src="https://mdn.mozillademos.org/files/10823/paint.png" style="height: 26px; width: 123px;"></td> + <td> + <p><code><a href="/ja/docs/Web/CSS/color">color</a></code></p> + </td> + </tr> + <tr> + <td>個別のレイヤーで描画されるプロパティは、再描画が発生しない。更新はコンポジションで制御される。</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/10827/recalculate-style.png" style="height: 26px; width: 123px;"> <img alt="" src="https://mdn.mozillademos.org/files/10835/layout-faint.png" style="height: 52px; width: 123px;"> <img alt="" src="https://mdn.mozillademos.org/files/10839/paint-faint.png" style="height: 26px; width: 123px;"></td> + <td><code><a href="/ja/docs/Web/CSS/transform">transform</a></code><br> + <code><a href="/ja/docs/Web/CSS/opacity">opacity</a></code></td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><a href="http://csstriggers.com/">CSS Triggers</a> の Web サイトで、各 CSS プロパティでどれだけのウォーターフォールが発生するかをまとめています。WebKit 固有の情報ですが、ほとんどはすべての最新ブラウザで同じです。</p> +</div> + +<h2 id="An_example.3A_margin_versus_transform" name="An_example.3A_margin_versus_transform">例: margin と transform</h2> + +<p>本章では、<a href="/ja/docs/Tools/Performance/Waterfall">ウォーターフォール</a>が <code><a href="/ja/docs/Web/CSS/margin">margin</a></code> を使用したアニメーションと <code><a href="/ja/docs/Web/CSS/transform">transform</a></code> を使用したアニメーションの違いを、どのように明らかにできるかを示します。</p> + +<p>このシナリオは、<code>margin</code> を使用したアニメーションは例外なく悪いアイデアであると納得させる意図はありません。サイトを描画するためにブラウザが何を行っているかをツールがどのようにして明らかにするか、およびパフォーマンスの問題の診断や解決のためにその情報をどのように適用できるかを示すものです。</p> + +<p>自身でも試してみたい場合は、デモ Web サイトが<a href="http://mdn.github.io/performance-scenarios/animation-transform-margin/index.html">こちら</a>にあります。サンプルは以下のようなものです:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/11029/css-animations-demo.png" style="display: block; height: 677px; margin-left: auto; margin-right: auto; width: 1000px;">ここには 2 つのコントロールがあります。アニメーションを開始/停止するボタンと、<code>margin</code> のアニメーションまたは <code>transform</code> のアニメーションを選択するラジオボタンです。</p> + +<p>ページ上には複数の要素を置いており、それらに <code><a href="/ja/docs/Web/CSS/linear-gradient">linear-gradient</a></code> の背景と <code><a href="/ja/docs/Web/CSS/box-shadow">box-shadow</a></code> を追加しています。これは、双方のプロパティは描画のコストが比較的高いためです。</p> + +<p>動画版のウォークスルーも用意しています:</p> + +<p>{{EmbedYouTube("Tvu6_j8Qzfk")}}</p> + +<h3 id="Animating_using_margin" name="Animating_using_margin">margin を使用したアニメーション</h3> + +<p>"Use margin" を選択したままでアニメーションを開始して、パフォーマンスツールを開いて記録を始めましょう。記録時間は数秒だけでかまいません。</p> + +<p>最初の記録を開きます。どのような結果になるかはマシンやシステム負荷に大きく依存しますが、おそらく以下のようになるでしょう:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10853/margin-recording.png" style="display: block; height: 237px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>ここでは 3 つの視点で示しています: (a) ウォーターフォールの概要、(b) フレームレート、(c) タイムラインの詳細 です。</p> + +<h4 id="Waterfall_overview" name="Waterfall_overview">ウォーターフォールの概要</h4> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10857/margin-timeline-overview.png" style="display: block; height: 58px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>これは、<a href="/ja/docs/Tools/Performance/Waterfall">ウォーターフォール</a>をコンパクトに表示したビューです。</p> + +<p>緑色が圧倒的に多いことは、<a href="/ja/docs/Tools/Performance/Timeline#timeline-color-coding">描画に多くの時間を費やしている</a>ことを示しています。</p> + +<p> </p> + +<h4 id="Frame_rate" name="Frame_rate">フレームレート</h4> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10859/margin-frame-rate.png" style="display: block; height: 64px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>これは、<a href="/ja/docs/Tools/Performance/Frame_rate">フレームレート</a>を表示します。ここでは平均フレームレートが 46.67fps であり、目標の 60fps をかなり下回っています。さらに悪いことにフレームレートが何度も 10 から 20 fps 台に低下しており、グラフがぎざぎざになっています。特にユーザとの対話が加わると、スムーズなアニメーションではなくなるでしょう。</p> + +<h4 id="Waterfall" name="Waterfall">ウォーターフォール</h4> + +<p>記録表示領域の残りの部分で、ウォーターフォールを表示します。ウォーターフォールをスクロールすると、以下のようなパターンが見られるでしょう:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10861/margin-timeline.png" style="display: block; height: 532px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>これは<a href="/ja/docs/Tools/Performance/Scenarios/Animating_CSS_properties#The_CSS_rendering_waterfall">レンダリングのウォーターフォール</a>を表します。それぞれのアニメーションフレームで、すべての要素のスタイルを再計算してからレイアウト処理を 1 回実施して、再描画を行います。</p> + +<p>ここでは、描画が特にパフォーマンスへ悪影響を与えていることがわかります。前出のスクリーンショットでは描画処理をハイライトしており、この処理は 13.11 ミリ秒かかっていることが右側のボックスでわかります。すべての処理に割り当てられた時間は 16.7 ミリ秒しかありませんので、高いフレームレートを維持できないのは驚くことではありません。</p> + +<p>ここで<a href="/ja/docs/Tools/Page_Inspector/How_to/Examine_and_edit_CSS">インスペクタを使用して</a> box-shadow を削除すると、描画時間にどのような影響があるかを実験できます。しかし次は、<code><a href="/ja/docs/Web/CSS/margin">margin</a></code> の代わりに <code><a href="/ja/docs/Web/CSS/transform">transform</a></code> を使用して高コストな描画を完全になくす方法を見ていきます。</p> + +<h3 id="Animating_using_transform" name="Animating_using_transform">transform を使用したアニメーション</h3> + +<p>Web ページのラジオボタンを "Use transform" に切り替えて、新たに記録してみましょう。すると、以下のようになるでしょう:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10863/transform-recording.png" style="display: block; height: 234px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<h4 id="Waterfall_overview_2" name="Waterfall_overview_2">ウォーターフォールの概要</h4> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10869/transform-timeline-overview.png" style="display: block; height: 57px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p><a href="/ja/docs/Tools/Performance/Scenarios/Animating_CSS_properties#Waterfall_overview">margin を使用した場合</a>と比べて緑色がとても少なく、また桃色がとても多くなっています。桃色は<a href="/ja/docs/Tools/Performance/Waterfall#timeline-color-coding">レイアウトやスタイルの再計算</a>でしょう。</p> + +<h4 id="Frame_rate_2" name="Frame_rate_2">フレームレート</h4> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10865/transform-frame-rate.png" style="display: block; height: 62px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p><a href="/ja/docs/Tools/Performance/Scenarios/Animating_CSS_properties#Frame_rate">margin を使用した場合</a>と比べて、良好であるように見えます。平均値は 60fps に近く、また開始付近で 1 回落ち込んでいることを除けば高いフレームレートを維持しています。</p> + +<h4 id="Waterfall_2" name="Waterfall_2">ウォーターフォール</h4> + +<p>タイムラインビューで、フレームレートが向上した理由が示されています。<a href="/ja/docs/Tools/Performance/Scenarios/Animating_CSS_properties#Waterfall">margin を使用した場合</a>と比べて、レイアウトや (この例ではさらに重要な) 描画に少しも時間を費やしていません:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10867/transform-timeline.png" style="display: block; height: 384px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>この例では <code>transform</code> を使用することでサイトのパフォーマンスが著しく向上しており、またどのようにおよびなぜ向上したかを、パフォーマンスツールで示すことができました。</p> diff --git a/files/ja/tools/performance/scenarios/index.html b/files/ja/tools/performance/scenarios/index.html new file mode 100644 index 0000000000..0b1a33b018 --- /dev/null +++ b/files/ja/tools/performance/scenarios/index.html @@ -0,0 +1,10 @@ +--- +title: シナリオ +slug: Tools/Performance/Scenarios +tags: + - TopicStub +translation_of: Tools/Performance/Scenarios +--- +<div>{{ToolsSidebar}}</div> + +<p>パフォーマンスシナリオ</p> diff --git a/files/ja/tools/performance/scenarios/intensive_javascript/index.html b/files/ja/tools/performance/scenarios/intensive_javascript/index.html new file mode 100644 index 0000000000..34cc1db672 --- /dev/null +++ b/files/ja/tools/performance/scenarios/intensive_javascript/index.html @@ -0,0 +1,231 @@ +--- +title: 集約的な JavaScript +slug: Tools/Performance/Scenarios/Intensive_JavaScript +translation_of: Tools/Performance/Scenarios/Intensive_JavaScript +--- +<div>{{ToolsSidebar}}</div><div class="summary"> +<p>デフォルトでブラウザはレイアウト、リフロー、ガベージコレクションだけでなく、ページ内のすべての JavaScript もひとつのスレッドで実行します。これは長い間実行する JavaScript がスレッドをブロックして、ページの不応答やユーザエクスペリエンスの悪化を招くおそれがあるということです。</p> + +<p><a href="/ja/docs/Tools/Performance/Frame_rate">フレームレート</a>および<a href="/ja/docs/Tools/Performance/Waterfall">ウォーターフォール</a>ツールを使用して、いつ JavaScript がパフォーマンスの問題を起こしているかを知る、および特に注意が必要な関数を選び出すことができます。</p> + +<p>本記事では長い間実行する JavaScript が応答性の問題を起こしているサンプルサイトを使用して、問題を修正するために 2 種類の方法を適用していきます。ひとつは長い間実行する JavaScript を複数の部品に分けて、それらのスケジューリングに <code><a href="/ja/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame</a></code> を使用する方法、もうひとつは <a href="/ja/docs/Web/API/Web_Workers_API/Using_web_workers">web worker</a> を使用して関数全体を別のスレッドに分ける方法です。</p> +</div> + +<p>自身でも試してみたい場合は、デモ Web サイトが<a class="external external-icon" href="http://mdn.github.io/performance-scenarios/js-worker/index.html">こちら</a>にあります。</p> + +<p>動画版のウォークスルーも用意しています:</p> + +<p>{{EmbedYouTube("Pcc6jQX6JDI")}}</p> + +<p>デモ Web サイトは以下のようなものです:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/11031/js-worker-demo.png" style="display: block; height: 677px; margin-left: auto; margin-right: auto; width: 1000px;">ここには 3 つのコントロールがあります:</p> + +<ul> + <li>JavaScript の実行方法を制御するラジオボタン。ブロックが発生するひとつの操作をメインスレッドで実行する、<code>requestAnimationFrame()</code> を使用して小規模な操作の集まりをメインスレッドで実行する、Worker を使用して別のスレッドで実行する。</li> + <li>"Do pointless computations!" と記載された、JavaScript を実行するボタン。</li> + <li>CSS アニメーションを開始・終了するボタン。これはブラウザに、バックグラウンドで実行するタスクを与えます。</li> +</ul> + +<p>ラジオボタンで "Use blocking call in main thread" を選択して、記録を始めましょう:</p> + +<ul> + <li>"Start animations" ボタンを押します。</li> + <li>パフォーマンスプロファイルの記録を始めます。</li> + <li>"Do pointless computations!" ボタンを 2~3 回押します。</li> + <li>プロファイルの記録を終了します。</li> +</ul> + +<p>どのような結果になるかはマシンにより異なりますが、おそらく以下のようになるでしょう:</p> + +<p><a id="js-blocking-overview" name="js-blocking-overview"><img alt="" src="https://mdn.mozillademos.org/files/10891/perf-js-blocking-overview.png" style="display: block; height: 113px; margin-left: auto; margin-right: auto; width: 800px;"></a></p> + +<p>この画像の上半分は<a href="/ja/docs/Tools/Performance/UI_Tour#Waterfall_overview">ウォーターフォールの概要</a>です。これは<a href="/ja/docs/Tools/Performance/Waterfall">ウォーターフォール</a>をコンパクトに表示したビューであり、記録中にブラウザが行った処理は何かを示します。<a href="/ja/docs/Tools/Performance/Waterfall#Markers">桃色はほとんどの場合 CSS の再計算、一部はリフローです</a>。これは、プロファイルで終始実行している CSS アニメーションです。また連続したの橙色のブロックが 3 つありますが、これは JavaScript を実行していることを表します。それぞれ、ボタンを押したときです。</p> + +<p>下半分はタイムラインの概要と時系列が合わせられており、<a href="/ja/docs/Tools/Performance/Frame_rate">フレームレート</a>を示しています。記録中のほとんどはフレームレートが良好ですが、ボタンを押すたびに大きく落ち込んでいます。</p> + +<p>それら 3 か所のうちひとつを選択して、メインのウォーターフォールビューで詳しく見ることができます:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10895/perf-js-blocking-waterfall.png" style="display: block; height: 306px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>ここではボタンを押したときに、ブラウザが JavaScript の関数をひとつまたは連続的に実行して、メインスレッドを 71.73 ミリ秒、言い換えるとフレーム 4 つ分の時間ブロックしています。</p> + +<p>どの関数でしょう? <a href="/ja/docs/Tools/Performance/Flame_Chart">フレームチャート</a>ビューに切り替えると、それがわかります:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10893/perf-js-blocking-flame-chart.png" style="display: block; height: 230px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>これは、その時点で実行している JS のコールスタックを表示します。スタックの一番上は <code>calculatePrimes()</code> という関数であり、ファイル名や行番号がわかります。以下に掲載したコードで、直近の呼び出し元を見てみましょう:</p> + +<pre class="brush: js">const iterations = 50; +const multiplier = 1000000000; + +function calculatePrimes(iterations, multiplier) { + var primes = []; + for (var i = 0; i < iterations; i++) { + var candidate = i * (multiplier * Math.random()); + var isPrime = true; + for (var c = 2; c <= Math.sqrt(candidate); ++c) { + if (candidate % c === 0) { + // not prime + isPrime = false; + break; + } + } + if (isPrime) { + primes.push(candidate); + } + } + return primes; +} + +function doPointlessComputationsWithBlocking() { + var primes = calculatePrimes(iterations, multiplier); + pointlessComputationsButton.disabled = false; + console.log(primes); +} +</pre> + +<p>ここではかなり大きな数に対して、(とても非効率な) 素数の判定を 50 回行っています。</p> + +<h2 id="Using_requestAnimationFrame" name="Using_requestAnimationFrame">requestAnimationFrame を使用する</h2> + +<p>この問題を解決するための最初の試みとして、関数をいくつかの自己充足した小さな関数に分割して、<code><a href="/ja/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame()</a></code> を使用してそれらをスケジューリングします。</p> + +<p><code>requestAnimationFrame()</code> は与えられた関数を、各フレームで再描画を行う直前に実行するようブラウザに指示します。それぞれの関数が適度に小さければ、ブラウザは実行時間を、フレーム間に与えられた時間内に収めることができるでしょう。</p> + +<p><code>calculatePrimes()</code> の分割はとてもシンプルです。別の関数で、それぞれの値が素数であるかの計算を行います:</p> + +<pre class="brush: js">function doPointlessComputationsWithRequestAnimationFrame() { + + function testCandidate(index) { + // finishing condition + if (index == iterations) { + console.log(primes); + pointlessComputationsButton.disabled = false; + return; + } + // test this number + var candidate = index * (multiplier * Math.random()); + var isPrime = true; + for (var c = 2; c <= Math.sqrt(candidate); ++c) { + if (candidate % c === 0) { + // not prime + isPrime = false; + break; + } + } + if (isPrime) { + primes.push(candidate); + } + // schedule the next + var testFunction = testCandidate.bind(this, index + 1); + window.requestAnimationFrame(testFunction); + } + + var primes = []; + var testFunction = testCandidate.bind(this, 0); + window.requestAnimationFrame(testFunction); +}</pre> + +<p>こちらのバージョンを試してみましょう。"Use requestAnimationFrame" と記載されたラジオボタンを選択して、新たにプロファイルを記録します。すると、記録は以下のようになるでしょう:</p> + +<p><a id="js-raf-overview" name="js-raf-overview"><img alt="" src="https://mdn.mozillademos.org/files/10897/perf-js-raf-overview.png" style="display: block; height: 112px; margin-left: auto; margin-right: auto; width: 800px;"></a></p> + +<p>これはまさに、私たちが期待していたものです。<a href="#js-blocking-overview">一続きの橙色のブロック</a>に代わり、ボタンを押すたびにとても短い橙色のブロックがたくさん並んでいます。橙色のブロックは 1 個ずつのフレームに分かれて現れており、またそれぞれのブロックが、<code>requestAnimationFrame()</code> から呼び出された関数 1 個を表しています。なお、このプロファイルではボタンを 2 回しか押していないことに注意してください。</p> + +<p>関数の呼び出しは CSS アニメーションに由来する桃色のブロックの間に挟み込まれており、またそれぞれの関数は、全体のフレームレートを落とすことなく処理できるほど十分に小さくなっています。</p> + +<p>ここでは <code>requestAnimationFrame</code> が応答性の問題の解決策として機能しましたが、潜在的な問題点が 2 つあります:</p> + +<ul> + <li>長い間実行する関数を、個別の自己充足した関数に分割することが難しい場合があります。今回のシンプルなケースでも、より複雑なコードになりました。</li> + <li>分割したバージョンでは、実行時間が長くなります。実は、処理にどれだけかかるかをかなり正確に言うことができます。処理は 50 回繰り返しており、またブラウザは 1 秒間に約 60 個のフレームを生成します。よって、すべての計算を実行するためにはほぼ 1 秒かかり、これはユーザエクスペリエンスやプロファイルから明らかになります。</li> +</ul> + +<h2 id="Using_web_workers" name="Using_web_workers">Web Worker を使用する</h2> + +<p>ここでは、Web Worker を使用して問題を解決します。Web Worker を使用すると、別のスレッドで JavaScript を実行できます。メインスレッドと Worker スレッドは互いに直接呼び出すことはできませんが、非同期メッセージ API を使用して通信できます。</p> + +<p>メインスレッドのコードは以下のようになります:</p> + +<pre class="brush: js">const iterations = 50; +const multiplier = 1000000000; + +var worker = new Worker("js/calculate.js"); + +function doPointlessComputationsInWorker() { + + function handleWorkerCompletion(message) { + if (message.data.command == "done") { + pointlessComputationsButton.disabled = false; + console.log(message.data.primes); + worker.removeEventListener("message", handleWorkerCompletion); + } + } + + worker.addEventListener("message", handleWorkerCompletion, false); + + worker.postMessage({ + "multiplier": multiplier, + "iterations": iterations + }); +}</pre> + +<p>元のコードと比べたときの主な違いは、以下のものが必要であることです:</p> + +<ul> + <li>Worker を作成する</li> + <li>計算の準備ができたときに、Worker へメッセージを送信する</li> + <li>"done" メッセージをリッスンする。これは、Worker が完了したことを示すメッセージです。</li> +</ul> + +<p>また、新たに "calculate.js" ファイルが必要であり、こちらは以下のようになります:</p> + +<pre class="brush: js">self.addEventListener("message", go); + +function go(message) { + var iterations = message.data.iterations; + var multiplier = message.data.multiplier; + primes = calculatePrimes(iterations, multiplier); + + self.postMessage({ + "command":"done", + "primes": primes + }); +} + +function calculatePrimes(iterations, multiplier) { + var primes = []; + for (var i = 0; i < iterations; i++) { + var candidate = i * (multiplier * Math.random()); + var isPrime = true; + for (var c = 2; c <= Math.sqrt(candidate); ++c) { + if (candidate % c === 0) { + // not prime + isPrime = false; + break; + } + } + if (isPrime) { + primes.push(candidate); + } + } + return primes; +}</pre> + +<p>Worker では処理の開始を指示するメッセージをリッスンする、および処理が完了したときに "done" メッセージを送ることが必要です。実際に計算を行っている部分のコードは、最初のバージョンのコードと完全に同じです。</p> + +<p>このバージョンはどのように実行されるのでしょう? ラジオボタンを "Use a worker" に切り替えて、新たにプロファイルを記録してください。結果は以下のようになるでしょう:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10899/perf-js-worker-overview.png" style="display: block; height: 112px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>このプロファイルでは、ボタンを 3 回押しています。ウォーターフォールの概要で<a href="#js-blocking-overview">元のバージョンと比べると</a>、ボタンを押したときにはとても短い橙色のマーカーが 2 個あることがわかります:</p> + +<ul> + <li>click イベントの処理と Worker の処理開始を行う、<code>doPointlessComputationsInWorker()</code> 関数</li> + <li>Worker が "done" を発信したときに実行される、<code>handleWorkerCompletion()</code> 関数</li> +</ul> + +<p>これら 2 つの関数の間で Worker は素数の判定を行っていますが、メインスレッドの応答性には少しも影響を与えていないように見受けられます。これはあり得ないと思うかもしれませんが、Worker は別のスレッドで実行しますのでマルチコアプロセッサの利点を享受できます。これはシングルスレッドの Web サイトでは得られません。</p> + +<p>Web Worker の主な制限は、Worker で実行するコードでは DOM API を使用できないことです。</p> |