现代浏览器设备集成与性能测量全解析
1. 现代浏览器设备集成概述
现代网页浏览器平台提供了一系列 API,可用于与各种设备信息和功能进行交互,具体包括:
- 电池状态
- 网络状态
- 地理位置
- 设备剪贴板
- 内容共享
- 触觉反馈
不过,在当前阶段,部分 API 的支持情况并不理想,有些仍处于实验阶段,因此暂不建议在生产环境的应用程序中使用。而且,即便某些浏览器(如 Chrome)支持特定的 API,但如果设备本身不具备相应的功能,这些 API 也无法正常工作。例如,Chrome 虽然很好地支持了振动 API,但在没有振动功能的笔记本电脑或其他设备上,该 API 就无法发挥作用。
2. 读取电池状态
2.1 问题
你希望在应用程序中显示设备的电池充电状态。
2.2 解决方案
使用电池状态 API。该 API 可能并非所有浏览器都支持,你可以访问 CanIUse 网站获取最新的兼容性数据。
具体操作步骤如下:
1.
创建 HTML 占位元素
:用于显示电池状态,示例代码如下:
<ul>
<li>Battery charge level:<span id="battery-level">--</span></li>
<li>Battery charge status:<span id="battery-charging">--</span></li>
</ul>
-
查询电池状态 API
:通过调用
navigator.getBattery方法来查询电池状态,该方法返回一个 Promise,解析后可得到包含电池信息的对象。示例代码如下:
const batteryLevelItem = document.querySelector('#battery-level');
const batteryChargingItem = document.querySelector('#battery-charging');
navigator.getBattery().then(battery => {
// Battery level is a number between 0 and 1. Multiply by 100 to convert it to
// a percentage.
batteryLevelItem.textContent = `${battery.level * 100}%`;
batteryChargingItem.textContent = battery.charging ? 'Charging' : 'Not charging';
});
-
处理电池状态变化
:当电池电量或充电状态发生变化时,需要更新 UI。可以监听
levelchange和chargingchange事件,并在事件触发时更新相应的 DOM 元素。示例代码如下:
battery.addEventListener('levelchange', () => {
batteryLevelItem.textContent = `${battery.level * 100}%`;
});
battery.addEventListener('chargingchange', () => {
batteryChargingItem.textContent = battery.charging ? 'Charging' : 'Not charging';
});
2.3 讨论
在当前阶段,部分浏览器可能完全不支持该 API。你可以使用以下代码检查用户的浏览器是否支持电池状态 API:
if ('getBattery' in navigator) {
// request the battery status here
} else {
// it's not supported
}
电池对象还包含一些其他属性,例如:
-
chargingTime
:如果电池正在充电,该属性表示电池完全充满所需的剩余秒数;如果电池未充电,该属性的值为 Infinity。
-
dischargingTime
:如果电池正在放电,该属性表示电池完全耗尽所需的剩余秒数;如果电池未放电,该属性的值为 Infinity。
这两个属性也有各自的变化事件,分别为
chargingtimechange
和
dischargingtimechange
。利用电池状态 API 提供的信息,你可以执行许多操作,例如在电池电量较低时禁用后台任务或其他耗电操作,或者提示用户保存更改等。
3. 读取网络状态
3.1 问题
你想了解用户的网络连接速度。
3.2 解决方案
使用网络信息 API 来获取用户网络连接的数据。示例代码如下:
if (navigator.connection.effectiveType === '4g') {
// User can perform high-bandwidth activities.
}
该 API 可能并非所有浏览器都支持,你可以访问 CanIUse 网站获取最新的兼容性数据。
3.3 讨论
网络信息包含在
navigator.connection
对象中。要大致了解网络连接的能力,可以检查
navigator.connection.effectiveType
属性。目前,根据下载速度,
navigator.connection.effectiveType
可能的值如下:
| 类型 | 速度 |
| ---- | ---- |
| slow - 2g | 最高 50 Kbps |
| 2g | 最高 70 Kbps |
| 3g | 最高 700 Kbps |
| 4g | 700 Kbps 及以上 |
这些值是根据实际用户数据测量计算得出的,规范中指出这些值未来可能会更新。你可以利用这些值大致判断设备的网络能力,例如,
effectiveType
为
slow - 2g
时,可能无法处理高清视频流等高带宽活动。
当页面打开时,如果网络连接发生变化,
navigator.connection
对象会触发一个变化事件。你可以监听该事件,并根据接收到的新网络连接信息调整应用程序。
4. 获取设备位置
4.1 问题
你希望获取设备的地理位置。
4.2 解决方案
使用地理位置 API 来获取设备的经纬度位置。该 API 暴露了
navigator.geolocation
对象,可使用
getCurrentPosition
方法请求用户的位置。这是一个基于回调的 API,
getCurrentPosition
方法接受两个参数:第一个参数是成功回调函数,第二个参数是错误回调函数。示例代码如下:
navigator.geolocation.getCurrentPosition(position => {
console.log('Latitude: ' + position.coords.latitude);
console.log('Longitude: ' + position.coords.longitude);
}, error => {
// Either the user denied permission, or the device location could not
// be determined.
console.log(error);
});
该 API 需要用户的授权。首次调用
getCurrentPosition
时,浏览器会询问用户是否允许共享其位置。如果用户拒绝授权,地理位置请求将失败,浏览器会调用错误回调函数。
如果你想提前检查授权状态,以避免捕获错误,可以使用权限 API 来检查其状态。示例代码如下:
const permission = await navigator.permissions.query({
name: 'geolocation'
});
4.3 讨论
浏览器可以通过多种方式尝试检测用户的位置,例如使用设备的 GPS、WiFi 连接信息或 IP 地址。但在某些情况下(如用户使用 VPN),基于 IP 的地理位置定位可能无法返回设备的正确位置。
地理位置 API 在浏览器中的支持情况非常好,除非你针对的是旧版本浏览器,否则通常不需要检查功能支持情况。
除了坐标信息外,位置对象还包含一些其他有趣的信息,但并非所有设备都支持这些信息,例如:
-
altitude
:设备相对于海平面的海拔高度(以米为单位)
-
heading
:设备的罗盘方向(以度为单位)
-
speed
:如果设备正在移动,该属性表示设备的速度(以米/秒为单位)
你还可以通过调用
navigator.geolocation.watchCurrentPosition
方法来监听设备位置的变化。当位置发生变化时,浏览器会定期调用你传递给该方法的回调函数,并提供更新后的坐标信息。
需要注意的是,地理位置 API 只能获取设备的坐标(经纬度),无法确定具体的州、城市或地址。要实现这一点,你需要使用地理编码 API,该 API 并非浏览器内置的,市场上有许多外部地理编码 API 可供选择,如微软和谷歌提供的服务。地理编码是将地址转换为经纬度的过程,部分服务还支持反向地理编码,即将经纬度坐标转换为地址。
5. 在地图上显示设备位置
5.1 问题
你希望在地图上显示设备的位置。
5.2 解决方案
使用 Google Maps API 或 OpenStreetMaps 等服务生成地图,并将从地理位置 API 获取的经纬度坐标传递给这些服务。
以 Google Maps Embed API 为例,你需要先在 Google Developers 网站上注册一个 API 密钥。具体操作步骤如下:
1.
请求设备位置
:在成功回调函数中创建一个 iframe 元素,并将其添加到文档中。示例代码如下:
// Assuming you have a placeholder element in the page with the ID 'map'
const map = document.querySelector('#map');
navigator.geolocation.getCurrentPosition(position => {
const { latitude, longitude } = position.coords;
// Adjust the iframe size as desired.
const iframe = document.createElement('iframe');
iframe.width = 450;
iframe.height = 250;
// The map type is part of the URL path.
const url = new URL('https://www.google.com/maps/embed/v1/place');
// The 'key' parameter contains your API key.
url.searchParams.append('key', 'YOUR_GOOGLE_MAPS_API_KEY');
// The 'q' parameter contains the latitude and longitude coordinates
// separated by a comma.
url.searchParams.append('q', `${latitude},${longitude}`);
iframe.src = url;
map.appendChild(iframe);
});
5.3 讨论
你可以参考 Google 的相关文章,了解如何正确保护 Google Maps API 密钥。在获取设备位置后,除了 Google Maps Embed API,还有许多其他的地图集成方式可供选择,例如 Google Maps 的其他类型 API、Mapbox 或 OpenStreetMap 等服务。你还可以集成地理编码 API,以在地图上显示带有实际地址的标记。
6. 文本复制与粘贴
6.1 问题
你希望在文本区域中添加复制和粘贴功能,用户能够选中一些文本并进行复制,粘贴时应替换当前选中的文本。
6.2 解决方案
使用剪贴板 API 与文本区域内的选中文本进行交互。你可以在用户界面中添加复制和粘贴按钮,并调用剪贴板 API 中的相应功能。
复制文本的示例代码如下:
async function copySelection(textarea) {
const { selectionStart, selectionEnd } = textarea;
const selectedText = textarea.value.slice(selectionStart, selectionEnd);
try {
await navigator.clipboard.writeText(selectedText);
} catch (error) {
console.error('Clipboard error:', error);
}
}
粘贴文本的示例代码如下:
async function pasteToSelection(textarea) {
const currentValue = textarea.value;
const { selectionStart, selectionEnd } = textarea;
try {
const clipboardValue = await navigator.clipboard.readText();
const newValue = currentValue.slice(0, selectionStart)
+ clipboardValue + currentValue.slice(selectionEnd);
textarea.value = newValue;
} catch (error) {
console.error('Clipboard error:', error);
}
}
该 API 可能并非所有浏览器都完全支持,你可以访问 CanIUse 网站获取最新的兼容性数据。
6.3 讨论
需要注意的是,尽管你没有对
navigator.clipboard.writeText
的返回值进行处理,但仍然需要等待该 Promise 完成,这是为了处理 Promise 被拒绝并抛出错误的情况。
在粘贴文本时,还需要注意以下两种情况:
- 如果没有选中任何文本,但文本区域具有焦点,文本将粘贴到光标位置。
- 如果文本区域没有焦点,文本将粘贴到文本区域值的末尾。
由于通过编程方式读取系统剪贴板可能涉及隐私问题,因此需要用户的授权。首次尝试从剪贴板读取数据时,浏览器会询问用户是否允许。如果用户允许,剪贴板操作将完成;如果用户拒绝授权,剪贴板 API 返回的 Promise 将被拒绝并抛出错误。
如果你想避免授权错误,可以使用权限 API 检查用户是否已授予从系统剪贴板读取数据的权限。示例代码如下:
const permission = await navigator.permissions.query({
name: 'clipboard-read'
});
if (permission.state !== 'denied') {
// Continue with the clipboard read operation.
}
权限对象的
state
属性可能有以下三个值:
-
granted
:用户已明确授予权限。
-
denied
:用户已明确拒绝权限。
-
prompt
:用户尚未被询问是否授予权限。
如果
permission.state
的值为
prompt
,当你首次尝试执行剪贴板读取操作时,浏览器会自动提示用户。
7. 使用 Web Share API 共享内容
7.1 问题
你希望为用户提供一种便捷的方式,使用设备的原生共享功能来共享链接。
7.2 解决方案
使用 Web Share API 来共享内容。该 API 可能并非所有浏览器都支持,你可以访问 CanIUse 网站获取最新的兼容性数据。
示例代码如下:
if ('share' in navigator) {
navigator.share({
title: 'Web API Cookbook',
text: 'Check out this awesome site!',
url: 'https://browserapis.dev'
});
}
在支持该 API 的设备和浏览器上,调用此方法会弹出一个熟悉的共享界面,用户可以通过多种方式共享链接。
7.3 讨论
共享界面的外观会因设备和操作系统的不同而有所差异。例如,在运行 macOS 14 的计算机上,共享界面会呈现出特定的样式。
8. 使设备振动
8.1 问题
你希望在应用程序中添加一些触觉反馈,让用户的设备振动。
8.2 解决方案
使用振动 API 以编程方式使设备振动。该 API 可能并非所有浏览器都支持,你可以访问 CanIUse 网站获取最新的兼容性数据。
触发单次振动的示例代码如下:
// A single vibration for 500ms
navigator.vibrate(500);
触发一系列振动的示例代码如下:
// Vibrate for 500ms three times, with a 250ms pause in between
navigator.vibrate([500, 250, 500, 250, 500]);
8.3 讨论
某些不具备振动功能的设备(如 MacBook Pro 上的 Chrome)也支持该 API,但调用
navigator.vibrate
方法不会产生任何效果,也不会抛出错误。
如果一系列振动正在进行,你可以调用
navigator.vibrate(0)
来取消正在进行的振动。
与自动播放视频类似,页面首次加载时不能自动触发振动,用户必须与页面进行某种交互后才能触发振动。
9. 获取设备方向
9.1 问题
你想确定设备是处于纵向还是横向方向。
9.2 解决方案
使用
screen.orientation.type
属性来获取设备的方向,或者使用
screen.orientation.angle
属性来获取设备相对于其自然方向的旋转角度。
9.3 讨论
screen.orientation.type
根据设备及其方向可能有以下四个值:
| 类型 | 角度 | 适用设备 |
| ---- | ---- | ---- |
| portrait - primary | 0 度 | 自然方向为纵向的设备(如手机) |
| portrait - secondary | 180 度 | 自然方向为纵向的设备(如手机) |
| landscape - primary | 90 度 | 自然方向为纵向的设备(如手机) |
| landscape - secondary | 270 度 | 自然方向为纵向的设备(如手机) |
对于自然方向为横向的设备(如某些平板电脑),这些值会相反:
| 类型 | 角度 | 适用设备 |
| ---- | ---- | ---- |
| landscape - primary | 0 度 | 自然方向为横向的设备(如平板电脑) |
| landscape - secondary | 180 度 | 自然方向为横向的设备(如平板电脑) |
| portrait - primary | 90 度 | 自然方向为横向的设备(如平板电脑) |
| portrait - secondary | 270 度 | 自然方向为横向的设备(如平板电脑) |
screen.orientation
对象还有一个
change
事件,你可以监听该事件以获取设备方向的变化通知。
10. 浏览器内置性能测量工具概述
在 JavaScript 应用程序中,有许多第三方工具可用于测量性能,但浏览器本身也提供了一些方便的工具来捕获性能指标:
-
导航计时 API
:用于捕获页面初始加载的性能数据,你可以检查页面加载所需的时间、DOM 变得可交互所需的时间等。该 API 返回一组时间戳,指示页面加载过程中每个事件发生的时间。
-
资源计时 API
:允许你检查下载资源和进行网络请求所需的时间,涵盖了页面资源(如 HTML 文件、CSS 文件、JavaScript 文件和图像)以及异步请求(如使用 Fetch API 进行的请求)。
-
用户计时 API
:用于计算任意操作的经过时间。你可以创建性能标记(表示时间点)和测量值(表示标记之间的计算持续时间)。
所有这些 API 都会在页面的缓冲区中创建性能条目,这是一个包含所有类型性能条目的单一集合。你可以随时检查这个缓冲区,还可以使用
PerformanceObserver
异步监听新性能条目的添加。
性能条目使用高精度时间戳,时间以毫秒为单位,在某些浏览器中,还可以包含具有微秒精度的小数部分。在浏览器中,这些时间戳存储为
DOMHighResTimeStamp
对象,这些数字从页面加载时开始为零,表示自页面加载以来某个特定条目发生的时间。
综上所述,现代浏览器提供了丰富的设备集成和性能测量功能,开发者可以根据实际需求合理利用这些 API 来提升应用程序的用户体验和性能表现。在使用这些 API 时,需要注意其兼容性和权限问题,以确保应用程序在不同环境下的稳定性和安全性。
现代浏览器设备集成与性能测量全解析
11. 导航计时 API 详解
导航计时 API 是捕获页面初始加载性能数据的重要工具。它能帮助我们了解页面从开始加载到各个关键阶段所花费的时间。
11.1 关键时间戳
导航计时 API 会返回一系列关键的时间戳,以下是一些重要的时间戳及其含义:
| 时间戳 | 含义 |
| ---- | ---- |
|
navigationStart
| 表示浏览器开始导航到当前页面的时间点,是整个导航过程的起点。 |
|
fetchStart
| 浏览器开始获取资源的时间,这个资源可能是 HTML 文件、重定向过程中的资源等。 |
|
responseStart
| 浏览器开始接收到服务器响应的第一个字节的时间。 |
|
domInteractive
| DOM 树构建完成,页面可以进行交互的时间点。 |
|
domContentLoadedEventStart
| DOMContentLoaded 事件开始触发的时间。 |
|
domContentLoadedEventEnd
| DOMContentLoaded 事件结束的时间。 |
|
loadEventStart
| Load 事件开始触发的时间。 |
|
loadEventEnd
| Load 事件结束的时间,标志着页面完全加载完成。 |
11.2 获取时间戳示例
我们可以通过以下代码获取这些时间戳:
const navigationEntry = performance.getEntriesByType('navigation')[0];
if (navigationEntry) {
console.log('Navigation Start:', navigationEntry.navigationStart);
console.log('Fetch Start:', navigationEntry.fetchStart);
console.log('Response Start:', navigationEntry.responseStart);
console.log('DOM Interactive:', navigationEntry.domInteractive);
console.log('DOM Content Loaded Event Start:', navigationEntry.domContentLoadedEventStart);
console.log('DOM Content Loaded Event End:', navigationEntry.domContentLoadedEventEnd);
console.log('Load Event Start:', navigationEntry.loadEventStart);
console.log('Load Event End:', navigationEntry.loadEventEnd);
}
通过分析这些时间戳,我们可以找出页面加载过程中的瓶颈。例如,如果
responseStart
和
fetchStart
之间的时间间隔过长,可能是网络请求存在问题;如果
domInteractive
到
loadEventEnd
时间过长,可能是页面中有大量的资源加载或脚本执行耗时。
12. 资源计时 API 深入分析
资源计时 API 让我们能够详细了解页面中各个资源的加载情况。
12.1 资源类型
资源计时 API 涵盖的资源类型丰富,包括但不限于:
- HTML 文件
- CSS 文件
- JavaScript 文件
- 图像文件
- 异步请求(如使用 Fetch API 进行的请求)
12.2 获取资源加载时间示例
以下代码展示了如何获取页面中所有资源的加载时间:
const resourceEntries = performance.getEntriesByType('resource');
resourceEntries.forEach(entry => {
console.log('Resource Name:', entry.name);
console.log('Start Time:', entry.startTime);
console.log('Response End Time:', entry.responseEnd);
console.log('Duration:', entry.duration);
});
通过这些信息,我们可以优化资源加载策略。例如,如果某个 JavaScript 文件加载时间过长,可以考虑将其拆分成多个小文件,或者使用异步加载的方式。
13. 用户计时 API 的应用
用户计时 API 可以让我们自定义性能测量点,计算任意操作的经过时间。
13.1 创建性能标记和测量值
我们可以通过以下步骤使用用户计时 API:
1.
创建性能标记
:
performance.mark('startOperation');
// 这里是需要测量的操作代码
for (let i = 0; i < 1000000; i++) {
// 一些操作
}
performance.mark('endOperation');
- 创建测量值 :
performance.measure('operationDuration', 'startOperation', 'endOperation');
- 获取测量结果 :
const measurement = performance.getEntriesByName('operationDuration')[0];
if (measurement) {
console.log('Operation Duration:', measurement.duration);
}
通过用户计时 API,我们可以精确测量应用程序中特定代码块的执行时间,从而有针对性地进行性能优化。
14. 性能条目缓冲区与 PerformanceObserver
所有的性能 API(导航计时 API、资源计时 API、用户计时 API)都会在页面的缓冲区中创建性能条目。这个缓冲区是一个包含所有类型性能条目的单一集合。
14.1 检查性能条目缓冲区
我们可以随时检查这个缓冲区,获取其中的性能条目:
const allEntries = performance.getEntries();
allEntries.forEach(entry => {
console.log('Entry Name:', entry.name);
console.log('Entry Type:', entry.entryType);
console.log('Entry Duration:', entry.duration);
});
14.2 使用 PerformanceObserver 监听新条目
PerformanceObserver
可以让我们异步监听新性能条目的添加。以下是一个简单的示例:
const observer = new PerformanceObserver((list, observer) => {
const entries = list.getEntries();
entries.forEach(entry => {
console.log('New Performance Entry:', entry.name);
});
});
observer.observe({ entryTypes: ['navigation', 'resource', 'mark', 'measure'] });
通过
PerformanceObserver
,我们可以实时监控性能变化,及时发现性能问题。
15. 性能优化建议
基于以上对浏览器性能测量工具的了解,我们可以给出以下性能优化建议:
1.
优化页面加载时间
:
- 压缩 HTML、CSS 和 JavaScript 文件,减少文件大小。
- 合并和压缩图像,使用合适的图像格式(如 WebP)。
- 优化服务器配置,减少响应时间。
- 使用 CDN(内容分发网络)加速资源下载。
2.
优化资源加载
:
- 异步加载非关键的 JavaScript 文件,避免阻塞页面渲染。
- 合理使用缓存,减少重复资源的下载。
3.
优化代码执行
:
- 避免在主线程中执行耗时的操作,使用 Web Workers 处理复杂计算。
- 优化算法和数据结构,减少代码执行时间。
16. 性能测量流程总结
下面是一个 mermaid 格式的流程图,总结了使用浏览器性能测量工具的一般流程:
graph TD
A[开始] --> B[选择性能测量 API]
B --> C{选择哪种 API}
C -->|导航计时 API| D[捕获页面初始加载性能数据]
C -->|资源计时 API| E[检查资源加载和网络请求时间]
C -->|用户计时 API| F[计算任意操作经过时间]
D --> G[分析关键时间戳]
E --> H[分析资源加载情况]
F --> I[创建性能标记和测量值]
G --> J[找出页面加载瓶颈]
H --> K[优化资源加载策略]
I --> L[优化特定代码块性能]
J --> M[采取优化措施]
K --> M
L --> M
M --> N[再次测量性能]
N --> O{性能是否提升}
O -->|是| P[结束]
O -->|否| B
通过这个流程,我们可以不断地优化应用程序的性能,提升用户体验。
总之,浏览器提供的这些性能测量工具为开发者提供了强大的手段来监控和优化应用程序的性能。开发者应该充分利用这些工具,根据实际情况进行性能分析和优化,从而打造出高性能、流畅的 Web 应用程序。同时,在使用设备集成 API 时,要注意兼容性和权限问题,确保应用程序在各种环境下都能稳定运行,为用户带来良好的使用体验。
超级会员免费看
7万+

被折叠的 条评论
为什么被折叠?



