diff options
Diffstat (limited to 'files/zh-cn')
-rw-r--r-- | files/zh-cn/web/api/navigator/sendbeacon/index.md | 135 |
1 files changed, 78 insertions, 57 deletions
diff --git a/files/zh-cn/web/api/navigator/sendbeacon/index.md b/files/zh-cn/web/api/navigator/sendbeacon/index.md index 13158ebca2..53795e66fd 100644 --- a/files/zh-cn/web/api/navigator/sendbeacon/index.md +++ b/files/zh-cn/web/api/navigator/sendbeacon/index.md @@ -4,92 +4,113 @@ slug: Web/API/Navigator/sendBeacon tags: - API - Beacon + - Method + - Navigator + - NeedsExample + - Networking + - Reference - Web Performance - sendBeacon translation_of: Web/API/Navigator/sendBeacon --- -<div> {{APIRef("HTML DOM")}}</div> +{{APIRef("HTML DOM")}} -<p><code><strong>navigator.sendBeacon()</strong></code> 方法可用于通过{{Glossary("HTTP")}}将少量数据异步传输到Web服务器。</p> +**`navigator.sendBeacon()`** 方法可用于通过 [HTTP POST](/zh-CN/docs/Web/HTTP/Methods/POST) 将少量数据{{glossary("Asynchronous", "异步")}}传输到 Web 服务器。 -<h2 id="语法">语法</h2> +它主要用于将统计数据发送到 Web 服务器,同时避免了用传统技术(如:{{domxref("XMLHttpRequest","XMLHttpRequest")}})发送分析数据的一些问题。 -<pre>navigator.sendBeacon(<em>url, </em><em>data</em>);</pre> +## 语法 -<h3 id="参数">参数</h3> +```js +navigator.sendBeacon(url); +navigator.sendBeacon(url, data); +``` -<dl> - <dt><code>url</code></dt> - <dd><code>url</code> 参数表明 <code>data</code> 将要被发送到的网络地址。</dd> -</dl> +### 参数 -<dl> - <dt><code>data</code></dt> - <dd><code>data</code> 参数支持发送 {{domxref("ArrayBuffer")}} 、 {{domxref("ArrayBufferView")}} 、 {{domxref("Blob")}}、 {{domxref("DOMString")}} 、 {{domxref("FormData")}} 或者 {{domxref("URLSearchParams")}} 类型的数据。</dd> -</dl> +- `url` + - : `url` 参数表明 `data` 将要被发送到的网络地址。 +- `data` {{Optional_inline}} + - : `data` 参数是将要发送的 {{jsxref("ArrayBuffer")}}、{{domxref("ArrayBufferView")}}、{{domxref("Blob")}}、{{domxref("DOMString")}}、{{domxref("FormData")}} 或 {{domxref("URLSearchParams")}} 类型的数据。 -<h3 id="返回值">返回值</h3> +### 返回值 -<p>当用户代理成功把数据加入传输队列时,<strong><code>sendBeacon()</code></strong> 方法将会返回 <code>true</code>,否则返回 <code>false</code>。</p> +当用户代理成功把数据加入传输队列时,**`sendBeacon()`** 方法将会返回 `true`,否则返回 `false`。 -<h2 id="描述">描述</h2> +## 描述 -<p>这个方法主要用于满足统计和诊断代码的需要,这些代码通常尝试在卸载(unload)文档之前向web服务器发送数据。过早的发送数据可能导致错过收集数据的机会。然而,对于开发者来说保证在文档卸载期间发送数据一直是一个困难。因为用户代理通常会忽略在 {{event("unload")}} 事件处理器中产生的异步 {{domxref("XMLHttpRequest")}}。</p> +这个方法主要用于满足统计和诊断代码的需要,这些代码通常尝试在卸载(unload)文档之前向web服务器发送数据。过早的发送数据可能导致错过收集数据的机会。然而,对于开发者来说保证在文档卸载期间发送数据一直是一个困难。因为用户代理通常会忽略在 {{event("unload")}} 事件处理器中产生的异步 {{domxref("XMLHttpRequest")}}。 -<p>为了解决这个问题, 统计和诊断代码通常要在 <code>unload</code> 或者 {{event("beforeunload")}} 事件处理器中发起一个同步 <code>XMLHttpRequest</code> 来发送数据。同步的 <code>XMLHttpRequest</code> 迫使用户代理延迟卸载文档,并使得下一个导航出现的更晚。下一个页面对于这种较差的载入表现无能为力。</p> +过去,为了解决这个问题, 统计和诊断代码通常要在 -<p>有一些技术被用来保证数据的发送。其中一种是通过在卸载事件处理器中创建一个图片元素并设置它的 src 属性的方法来延迟卸载以保证数据的发送。因为绝大多数用户代理会延迟卸载以保证图片的载入,所以数据可以在卸载事件中发送。另一种技术是通过创建一个几秒钟的 no-op 循环来延迟卸载并向服务器发送数据。</p> +- 发起一个同步 `XMLHttpRequest` 来发送数据。 +- 创建一个 {{HTMLElement("img")}} 元素并设置 `src`,大部分用户代理会延迟卸载(unload)文档以加载图像。 +- 创建一个几秒的 no-op 循环。 -<p>这些技术不仅编码模式不好,其中的一些甚至并不可靠而且会导致非常差的页面载入性能。</p> +上述的所有方法都会迫使用户代理延迟卸载文档,并使得下一个导航出现的更晚。下一个页面对于这种较差的载入表现无能为力。 -<p>下面的例子展示了一个理论上的统计代码——在卸载事件处理器中尝试通过一个同步的 <code>XMLHttpRequest</code> 向服务器发送数据。这导致了页面卸载被延迟。</p> +这就是 **`sendBeacon()`** 方法存在的意义。使用 **`sendBeacon()`** 方法会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能,这意味着: -<pre class="brush: js">window.addEventListener('unload', logData, false); +- 数据发送是可靠的。 +- 数据异步传输。 +- 不影响下一导航的载入。 -function logData() { - var client = new XMLHttpRequest(); - client.open("POST", "/log", false); // 第三个参数表明是同步的 xhr - client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8"); - client.send(analyticsData); -} -</pre> +数据是通过 [HTTP POST](/zh-CN/docs/Web/HTTP/Methods/POST) 请求发送的。 -<p>这就是 <strong><code>sendBeacon()</code></strong> 方法存在的意义。使用 <strong><code>sendBeacon() </code></strong>方法会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能。这就解决了提交分析数据时的所有的问题:数据可靠,传输异步并且不会影响下一页面的加载。此外,代码实际上还要比其他技术简单许多!</p> +### 在会话结束时发送统计数据 -<p>下面的例子展示了一个理论上的统计代码模式——通过使用 <strong><code>sendBeacon()</code></strong> 方法向服务器发送数据。</p> +网站通常希望在用户完成页面浏览后向服务器发送分析或诊断数据,最可靠的方法是在 {{event("visibilitychange")}} 事件发生时发送数据: -<pre class="brush: js">window.addEventListener('unload', logData, false); +```js +document.addEventListener('visibilitychange', function logData() { + if (document.visibilityState === 'hidden') { + navigator.sendBeacon('/log', analyticsData); + } +}); +``` -function logData() { - navigator.sendBeacon("/log", analyticsData); -} -</pre> +### 避免使用 unload 和 beforeunload -<h2 id="规范">规范</h2> +过去,许多网站使用 {{event("unload")}} 或 {{event("beforeunload")}} 事件以在会话结束时发送统计数据。然而这是不可靠的,在许多情况下(尤其是移动设备)浏览器不会产生 `unload`、`beforeunload` 或 `pagehide` 事件。下面列出了一种不触发上述事件的情况: -<table class="standard-table"> - <tbody> - <tr> - <th scope="col">Specification</th> - <th scope="col">Status</th> - <th scope="col">Comment</th> - </tr> - <tr> - <td>{{SpecName('Beacon', '#sec-sendBeacon-method', 'sendBeacon()')}}</td> - <td>{{Spec2('Beacon')}}</td> - <td>Initial definition</td> - </tr> - </tbody> -</table> +1. 用户加载了网页并与其交互。 +2. 完成浏览后,用户切换到了其它应用程序,而不是关闭选项卡。 +3. 随后,用户通过手机的应用管理器关闭了浏览器应用。 -<h2 id="浏览器兼容性">浏览器兼容性</h2> +此外,`unload` 事件与现代浏览器实现的往返缓存([bfcache](https://web.dev/bfcache/))不兼容。在部分浏览器(如:Firefox)通过在 bfcache 中排除包含 `unload` 事件处理器的页面来解决不兼容问题,但这存在性能损失。其它浏览器,例如 Safari 和 Android 上的 Chrome 浏览器则采取用户在同一标签页下导航至其它页面时不触发 `unload` 事件的方法来解决不兼容问题。 +Firefox 也会在 bfcache 中排除包含 `beforeunload` 事件处理器的页面。 +#### 使用 pagehide 作为回退 -<p>{{Compat("api.Navigator.sendBeacon")}}</p> +可使用 {{event("pagehide")}} 事件来代替部分浏览器未实现的 `visibilitychange` 事件。和 `beforeunload` 与 `unload` 事件类似,这一事件不会被可靠地触发(特别是在移动设备上),但它与 bfcache 兼容。 -<h2 id="相关链接">相关链接</h2> +## 示例 -<ul> - <li>{{domxref("navigator", "navigator")}}</li> -</ul> +示例代码使用 {{event("visibilitychange")}} 事件来调用 `sendBeacon()` 以发送统计数据。 + +```js +document.addEventListener('visibilitychange', function logData() { + if (document.visibilityState === 'hidden') { + navigator.sendBeacon('/log', analyticsData); + } +}); +``` + +## 规范 + +{{Specifications}} + +## 浏览器兼容性 + +{{Compat}} + +## 参见 + +- {{event("visibilitychange")}} 事件。 +- {{domxref("Beacon_API","Beacon API", "" , "true")}} 概述。 +- [Don't + lose user and app state, use Page Visibility](https://www.igvita.com/2015/11/20/dont-lose-user-and-app-state-use-page-visibility/) 解释了为什么你应该使用 `visibilitychange` 而不是 `beforeunload`/`unload`。 +- [网页生命周期 API](https://developers.google.com/web/updates/2018/07/page-lifecycle-api#developer-recommendations-for-each-state) 提供了有关在 Web 应用程序中处理网页生命周期行为的最佳实践。 +- [PageLifecycle.js](https://github.com/GoogleChromeLabs/page-lifecycle):处理跨浏览器网页生命周期行为不一致的 JavaScript 库。 +- [Back/forward cache](https://web.dev/bfcache/) 解释了什么是往返缓存,以及它对各种网页生命周期事件的影响。 |