1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
---
title: JavaScript Profiler
slug: Tools/Profiler
translation_of: Tools/Performance
translation_of_original: Tools/Profiler
---
<div>{{ToolsSidebar}}</div><p>使用Profiler工具找到你的JavaScript代码的瓶颈. Profiler会定期统计JavaScript样本的堆栈信息.</p>
<p>你可以通过在Web Developer菜单下选择Profiler来启动它. 在Linux和OS X下,你可以在Tools菜单下找到Web Developer,而在windows下,Web Developer则在FIrefox菜单下.</p>
<p>当Profiler被选择后,工具箱就会被打开.</p>
<h2 id="抽样分析器"><a name="sampling-profilers">抽样分析器</a></h2>
<p>JavaScript Profiler是一个抽样分析器. 这意味着它会定期对JavaScript引擎的状态取样, 并且记录取样时代码运行的堆栈信息. 统计学上, 我们运行可接受样本数量的函数,花费的时间相当于浏览器运行它的时间,所以你可以很好的从你的代码里找到瓶颈。<br>
<br>
<a name="profiling-example">例如,考虑这样一个程序:</a></p>
<pre class="brush: js">function doSomething() {
var x = getTheValue();
x = x + 1; // -> sample A
logTheValue(x);
}
function getTheValue() {
return 5;
}
function logTheValue(x) {
console.log(x); // -> sample B, sample C
}
doSomething();</pre>
<p>Suppose we run this program with the profiler active, and in the time it takes to run, the profiler takes three samples, as indicated in the inline comments above.</p>
<p>They're all taken from inside <code>doSomething()</code>, but the second two are inside the <code>logTheValue()</code> function called by <code>doSomething()</code>. So the profile would consist of three stack traces, like this:</p>
<pre>Sample A: doSomething()
Sample B: doSomething() > logTheValue()
Sample C: doSomething() > logTheValue()</pre>
<p>This obviously isn't enough data to tell us anything, but with a lot more samples we might be able to conclude that <code>logTheValue()</code> is the bottleneck in our code.</p>
<h2 id="Creating_a_profile">Creating a profile</h2>
<p>点击探查器中的秒表按钮来开始记录。当探查器正在记录时,秒表按钮是高亮状态。当我们再一次点击秒表按钮时,记录将停止并保存为一个新的Profile:</p>
<p style="text-align: center;"><img alt="" src="https://mdn.mozillademos.org/files/5977/Screen%20Shot%202013-08-26%20at%2010.35.47%20AM.png"></p>
<p>Once you've clicked "Stop", the new profile will open automatically:</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5981/Screen%20Shot%202013-08-26%20at%2011.07.18%20AM.png" style="display: block; margin-left: auto; margin-right: auto;"></p>
<p>This pane's divided into two parts:</p>
<ul>
<li>The left-hand side lists all the profiles you've captured and allows you to load each one. Just above this there are two buttons: the <em>stopwatch</em> button allows you to record a new profile while the <em>Import...</em> button allows you to import previously saved data. When profile is selected, you can save its data as a JSON file by clicking the <em>Save</em> button.</li>
<li>The right-hand side displays the currently loaded profile.</li>
</ul>
<h2 id="Analyzing_a_profile">Analyzing a profile</h2>
<p>The profile is split into two parts:</p>
<ul>
<li>the <a href="#profile-timeline" title="#profile-timeline">profile timeline</a></li>
<li>the <a href="#profile-details" title="#profile-details">profile details</a></li>
</ul>
<h3 id="Profile_timeline"><a name="profile-timeline">Profile timeline</a></h3>
<p>The profile timeline occupies the top part of the profile display:</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5987/timeline" style="display: block; margin-left: auto; margin-right: auto;">The horizontal axis is time, and the vertical axis is call stack size at that sample. Call stack represents the amount of active functions at the time when the sample was taken.</p>
<p>Red samples along the chart indicate the browser was unresponsive during that time, and a user would notice pauses in animations and responsiveness. If a profile has red samples, consider breaking this code up into several events, and look into using <a href="/en-US/docs/Web/API/window.requestAnimationFrame" title="/en-US/docs/Web/API/window.requestAnimationFrame">requestAnimationFrame</a> and <a href="/en-US/docs/Web/Guide/Performance/Using_web_workers" title="/en-US/docs/Web/Guide/Performance/Using_web_workers">Workers</a>.</p>
<p>You can examine a specific range within the profile by clicking and dragging inside the timeline:</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5989/Screen%20Shot%202013-08-26%20at%2011.17.59%20AM.png" style="display: block; margin-left: auto; margin-right: auto;"></p>
<p>A new button then appears above the timeline labeled "Sample Range [AAA, BBB]". Clicking that button zooms the profile, and the details view underneath it, to that timeslice:</p>
<p><br>
<img alt="" src="https://mdn.mozillademos.org/files/5991/Screen%20Shot%202013-08-26%20at%2011.18.03%20AM.png" style="display: block; margin-left: auto; margin-right: auto;"></p>
<h3 id="Profile_details"><a name="profile-details">Profile details</a></h3>
<p>The profile details occupy the bottom part of the profile display:</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5993/profiler-details-highligted.png" style="display: block; margin-left: auto; margin-right: auto;">When you first open a new sample, the sample pane contains a single row labeled "(total)", as in the screenshot above. If you click the arrow next to "(total)", you'll see a list of all the top-level functions which appear in a sample.</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5995/Screen%20Shot%202013-08-26%20at%2011.22.10%20AM.png"></p>
<p><strong>Running time</strong> shows the total number of samples in which this function appeared<a href="#footnote-1"><sup>1</sup></a>, followed by the percentage of all samples in the profile in which this function appeared. The first row above shows that there were 2021 samples in the entire profile, and the second row shows that 1914, or 94.7%, of them were inside the <code>detectImage()</code> function.</p>
<p><strong>Self</strong> shows the number of samples in which the sample was taken while executing this function itself, and not a function it was calling. In the <a href="#profiling-example" title="#profiling-example">simple example</a> above, <code>doSomething()</code> would have a <strong>Running time</strong> of 3 (samples A, B, and C), but a <strong>Self</strong> value of 1 (sample A).</p>
<p>The third column gives the name of the function along with the filename and line number (for local functions) or basename and domain name (for remote functions). Functions in gray are built-in browser functions: functions in black represent JavaScript loaded by the page. If you hover the mouse over a row you'll see an arrow to the right of the function's identifier: click the arrow and you'll be taken to the function source.</p>
<h3 id="Expanding_the_call_tree">Expanding the call tree</h3>
<p>In a given row, if there are any samples taken while we were in a function called by this function (that is, if <strong>Running Time</strong> is greater than <strong>Self</strong> for a given row) then an arrow appears to the left of the function's name, enabling you to expand the call tree.</p>
<p>In the <a href="#profiling-example" title="#profiling-example">simple example</a> above, the fully-expanded call tree would look like this:</p>
<table class="standard-table" style="height: 100px; width: 378px;">
<tbody>
<tr>
<td style="text-align: center;"><strong>Running Time</strong></td>
<td style="text-align: center;"><strong>Self</strong></td>
<td style="text-align: center;"> </td>
</tr>
<tr>
<td style="text-align: center;">3 100%</td>
<td style="text-align: center;">1</td>
<td style="text-align: center;">doSomething()</td>
</tr>
<tr>
<td style="text-align: center;">2 67%</td>
<td style="text-align: center;">2</td>
<td style="text-align: center;">logTheValue()</td>
</tr>
</tbody>
</table>
<p>To take a more realistic example: in the screenshot below, looking at the second row we can see that 1914 samples were taken inside the <code>detectImage()</code> function. But all of them were taken in functions called by <code>detectImage()</code> (the <strong>Self</strong> cell is zero). We can expand the call tree to find out which functions were actually running when most of the samples were taken:</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5999/bla.png" style="display: block; margin-left: auto; margin-right: auto;"></p>
<p>This tells us that 6 samples were taken when we were actually executing <code>detectAtScale(), </code>12 when we were executing <code>getRect()</code> and so on.</p>
<h2 id="Footnotes">Footnotes</h2>
<ol>
<li><a name="footnote-1">If the function is called multiple times from different sources, it will be represented multiple times in the Profiler output. So generic functions like <code>forEach</code> will appear multiple times in the call tree.</a></li>
</ol>
<p> </p>
|