aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/web/api/page_visibility_api/index.html
blob: 55e8f2c21142195409184c51087e2cf110406ac9 (plain)
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
---
title: 页面可见性 API
slug: Web/API/Page_Visibility_API
tags:
  - DOM
  - Intermediate
  - PageVisiblity
translation_of: Web/API/Page_Visibility_API
---
<p>{{DefaultAPISidebar("Page Visibility API")}}</p>

<p>使用选项卡式浏览,任何给定网页都有可能在后台,因此对用户不可见。页面可见性 API提供了您可以观察的事件,以便了解文档何时可见或隐藏,以及查看页面当前可见性状态的功能。</p>

<div class="note">
<p><strong>注意:</strong>页面可见性 API对于节省资源和提高性能特别有用,它使页面在文档不可见时避免执行不必要的任务。</p>
</div>

<p>当用户最小化窗口或切换到另一个选项卡时,API会发送{{event("visibilitychange")}}事件,让监听者知道页面状态已更改。你可以检测事件并执行某些操作或行为不同。例如,如果您的网络应用正在播放视频,则可以在用户将标签放入背景时暂停视频,并在用户返回标签时恢复播放。 用户不会在视频中丢失位置,视频的音轨不会干扰新前景选项卡中的音频,并且用户在此期间不会错过任何视频。</p>

<p>{{HTMLElement("iframe")}}的可见性状态与父文档相同。使用CSS属性(例如{{cssxref("display", "display: none;")}})隐藏<code>&lt;iframe&gt;</code>不会触发可见性事件或更改框架中包含的文档的状态。</p>

<h3 id="使用情景">使用情景</h3>

<p>一些例子:</p>

<ul>
 <li>网站有图片轮播效果,只有在用户观看轮播的时候,才会自动展示下一张幻灯片。</li>
 <li>显示信息仪表盘的应用程序不希望在页面不可见时轮询服务器进行更新。</li>
 <li>页面想要检测是否正在渲染,以便可以准确的计算网页浏览量</li>
 <li>当设备进入待机模式时,网站想要关闭设备声音(用户按下电源键关闭屏幕)</li>
</ul>

<p>开发者在过去使用不完善的代理来检测页面的可见性。比如,通过监听 {{event("blur")}} 和 {{event("focus")}} 事件来了解页面是否处于活动状态,但是它并没有告诉你页面是对用户隐藏的。页面可见性 API 解决了这个问题。</p>

<div class="note">
<p><strong>注意:</strong>虽然{{domxref("GlobalEventHandlers.onblur", "onblur")}}{{domxref("GlobalEventHandlers.onfocus", "onfocus")}}会告诉你用户是否切换窗口,但不一定意味着它是隐藏的。当用户切换选项卡或最小化包含选项卡的浏览器窗口时,页面才会隐藏。</p>
</div>

<h3 id="制定有助于后台页面性能的策略">制定有助于后台页面性能的策略</h3>

<p>在页面可见性API之外,用户代理会采取许多策略来减轻背景或隐藏选项卡对性能的影响。这些可能包括:</p>

<ul>
 <li>大多数浏览器不会调用被隐藏的标签页或{{ HTMLElement("iframe") }}框架当中{{domxref("Window.requestAnimationFrame", "requestAnimationFrame()")}}定义的回调函数,这会提升性能并且延长电池的使用寿命。</li>
 <li>在调用被隐藏的标签页或<code>iframe</code>框架中 {{domxref("WindowOrWorkerGlobalScope.setTimeout", "setTimeout()")}}等计时器会被加速。 See <a href="/zh-CN/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Reasons_for_delays_longer_than_specified">Reasons for delays longer than specified</a> for more details.</li>
 <li>Budget-based background timeout throttling is now available in modern browsers (Firefox 58+, Chrome 57+), placing an additional limit on background timer CPU usage. This operates in a similar way across modern browsers, with the details being as follows:
  <ul>
   <li>In Firefox, windows in background tabs each have their own time budget in milliseconds — a max and a min value of +50 ms and -150 ms, respectively. Chrome is very similar except that the budget is specified in seconds.</li>
   <li>Windows are subjected to throttling after 30 seconds, with the same throttling delay rules as specified for window timers (again, see <a href="/zh-CN/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Reasons_for_delays_longer_than_specified">Reasons for delays longer than specified</a>). In Chrome, this value is 10 seconds.</li>
   <li>Timer tasks are only permitted when the budget is non-negative.</li>
   <li>Once a timer's code has finished running, the duration of time it took to execute is subtracted from its window's timeout budget.</li>
   <li>The budget regenerates at a rate of 10 ms per second, in both Firefox and Chrome.</li>
  </ul>
 </li>
</ul>

<p>Some processes are exempt from this throttling behavior. In these cases, you can use the Page Visibility API to reduce the tabs' performance impact while they're hidden.</p>

<ul>
 <li>Tabs which are playing audio are considered foreground and aren’t throttled.</li>
 <li>Tabs running code that's using real-time network connections (<a href="/zh-CN/docs/Web/API/WebSockets_API">WebSockets</a> and <a href="/zh-CN/docs/Web/API/WebRTC_API">WebRTC</a>) go unthrottled in order to avoid closing these connections timing out and getting unexpectedly closed.</li>
 <li><a href="/zh-CN/docs/Web/API/IndexedDB_API">IndexedDB</a> processes are also left unthrottled in order to avoid timeouts.</li>
</ul>

<h2 id="示例">示例</h2>

<p>看一个 <a href="http://daniemon.com/tech/webapps/page-visibility/">在线的例子 </a>(带声音的视频)</p>

<p>在此例中,当你切换到另一个标签时视频会暂停,当你返回到当前标签时视频会再次播放,代码如下:</p>

<pre class="brush: js notranslate">// 设置隐藏属性和改变可见属性的事件的名称
var hidden, visibilityChange;
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
  hidden = "hidden";
  visibilityChange = "visibilitychange";
} else if (typeof document.msHidden !== "undefined") {
  hidden = "msHidden";
  visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
  hidden = "webkitHidden";
  visibilityChange = "webkitvisibilitychange";
}

var videoElement = document.getElementById("videoElement");

// 如果页面是隐藏状态,则暂停视频
// 如果页面是展示状态,则播放视频
function handleVisibilityChange() {
  if (document[hidden]) {
    videoElement.pause();
  } else {
    videoElement.play();
  }
}

// 如果浏览器不支持addEventListener 或 Page Visibility API 给出警告
if (typeof document.addEventListener === "undefined" || typeof document[hidden] === "undefined") {
  console.log("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
} else {
  // 处理页面可见属性的改变
  document.addEventListener(visibilityChange, handleVisibilityChange, false);

  // 当视频暂停,设置title
  // This shows the paused
  videoElement.addEventListener("pause", function(){
    document.title = 'Paused';
  }, false);

  // 当视频播放,设置title
  videoElement.addEventListener("play", function(){
    document.title = 'Playing';
  }, false);

}
</pre>

<h2 id="属性">属性</h2>

<dl>
 <dt>{{domxref("Document.hidden")}} {{ReadOnlyInline}}</dt>
 <dd>如果页面处于被认为是对用户隐藏状态时返回true,否则返回false。</dd>
 <dt>{{domxref("Document.visibilityState")}} {{ReadOnlyInline}}</dt>
 <dd>是一个用来展示文档当前的可见性的{{domxref("DOMString")}} 。该属性的值为以下值之一:
 <ul>
  <li><code>visible</code> : 页面内容至少是部分可见。 在实际中,这意味着页面是非最小化窗口的前景选项卡。</li>
  <li><code>hidden</code> : 页面内容对用户不可见。 在实际中,这意味着文档可以是一个后台标签,或是最小化窗口的一部分,或是在操作系统锁屏激活的状态下。</li>
  <li><code>prerender</code> : 页面内容正在被预渲染且对用户是不可见的(被document.hidden当做隐藏). 文档可能初始状态为prerender,但绝不会从其它值转为该值。&gt;</li>
  <li><span class="note">注释:有的浏览器不支持此功能</span><code>unloaded</code> : 页面正在从内存中卸载。</li>
  <li><span class="note">注释:有的浏览器不支持此功能</span></li>
 </ul>
 </dd>
 <dt>{{domxref("Document.onvisibilitychange")}}</dt>
 <dd>{{domxref("EventListener")}} 提供在{{event("visibilitychange")}} 事件被触发时要调用的代码。</dd>
</dl>

<pre class="brush: js notranslate">//startSimulation 和 pauseSimulation 在其他地方定义
function handleVisibilityChange() {
  if (document.hidden) {
    pauseSimulation();
  } else  {
    startSimulation();
  }
}

document.addEventListener("visibilitychange", handleVisibilityChange, false);
</pre>

<h2 id="规范">规范</h2>

<table class="standard-table">
 <thead>
  <tr>
   <th scope="col">Specification</th>
   <th scope="col">Status</th>
   <th scope="col">Comment</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>{{SpecName('Page Visibility API')}}</td>
   <td>{{Spec2('Page Visibility API')}}</td>
   <td>Initial definition.</td>
  </tr>
 </tbody>
</table>

<h2 id="浏览器兼容性">浏览器兼容性</h2>

<div>
<h3 id="Document.visibilityState"><code>Document.visibilityState</code></h3>

<div>


<p>{{Compat("api.Document.visibilityState")}}</p>
</div>
</div>

<h2 id="参考">参考</h2>

<ul>
 <li>Description of the <a href="http://blogs.msdn.com/b/ie/archive/2011/07/08/using-pc-hardware-more-efficiently-in-html5-new-web-performance-apis-part-2.aspx" title="Page Visibility on IEBlog">Page Visibility API</a> on the IEBlog.</li>
 <li>Description of the <a href="http://code.google.com/chrome/whitepapers/pagevisibility.html" title="Page Visibility API by Google">Page Visibility API</a> by Google</li>
</ul>