# Permissions API（navigator.permissions.query）

> navigator.permissions.query() 如何读取权限状态、处理不受支持的名称、监听变更，并在 API 缺失时回退。

`navigator.permissions.query()` 方法读取具名特性的权限状态。它返回的 Promise 会兑现为 `PermissionStatus`，其中 `state` 的值为 `"granted"`、`"denied"` 或 `"prompt"`。

## 支持情况

BCD 记录 Chrome 43、Firefox 46 和 Safari 16 起支持 `Permissions.query()`。各浏览器接受的权限名称不同，因此接口可用不等于某个名称可用。

## 语法

```js
const status = await navigator.permissions.query({ name: 'geolocation' });
```

这个方法接受一个 `PermissionDescriptor`，返回 `Promise<PermissionStatus>`。

## 参数

| 成员 | 类型 | 含义 |
|---|---|---|
| `name` | 字符串 | 要查询的权限名称。每个实现会注册自己支持的名称。 |

有些已注册权限使用带有更多成员的描述符类型。Permissions 规范把 `name` 定义为 `DOMString`，没有使用枚举，因为各实现支持的强力特性不同。

## 异常

关联文档并非完全活跃时，查询算法会用 `InvalidStateError` 拒绝 Promise。权限名称不受支持时，Promise 会用 `TypeError` 拒绝。转换传入的描述符时也可能用转换过程抛出的异常拒绝。

:::caution
规范原文写道：`If rootDesc["name"] is not supported, return a promise rejected with a TypeError`。查询当前浏览器可能未注册的名称时，要捕获这次拒绝（[Permissions 查询算法](https://www.w3.org/TR/permissions/#dom-permissions-query)）。
:::

## 示例

以下示例把查询入口不可用与 API 返回的权限状态分开处理。

### 读取状态并提供回退

这个函数先检测 API，再处理不受支持的名称。它返回回退值时不会把该情况写成用户拒绝。

```js
async function readGeolocationPermission() {
  if (!('permissions' in navigator)) {
    return 'unknown';
  }

  try {
    const status = await navigator.permissions.query({ name: 'geolocation' });
    return status.state;
  } catch (error) {
    return error instanceof TypeError ? 'unsupported-name' : 'unknown';
  }
}

console.log(await readGeolocationPermission());
```

回退值保留了查询入口缺失与规范所定义 `"denied"` 状态之间的区别。

### 监听状态变化

`PermissionStatus` 是 `EventTarget`。它的 `change` 事件触发后，页面可以读取新状态。

```js
if ('permissions' in navigator) {
  navigator.permissions.query({ name: 'notifications' }).then((status) => {
    console.log(status.state);
    status.addEventListener('change', () => console.log(status.state));
  }).catch(() => console.log('notifications permission query unavailable'));
} else {
  console.log('Permissions API unavailable');
}
```

如果浏览器提供 `Permissions`，但没有注册 `notifications`，代码也会进入拒绝分支。

## 另请参阅

- [Notification.requestPermission()](/zh/reference/notifications/permissions/)
- [Geolocation API](/zh/reference/capabilities/geolocation/)
- [Permissions 规范（W3C）](https://www.w3.org/TR/permissions/)
- [Permissions.query()（MDN）](https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query)