# 通知触发器（showTrigger）

> Chrome 的 Notification Triggers 提案在标志之后给 showNotification() 增加了什么、showTrigger 选项与 TimestampTrigger 类，以及开发为何终止。

通知触发器是 Chrome 的一项提案，用于把持久通知安排到未来某个时刻显示：`showNotification()` 将接受一个持有 `TimestampTrigger` 的 `showTrigger` 选项，浏览器在该时刻显示通知，不需要打开页面，也不需要推送消息。Chrome 的文档声明开发已经终止，该特性仍留在实验性标志之后，其他引擎都没有实现，因此所有正式发布的浏览器里都没有这个选项。

## 语法

```js
registration.showNotification(title, { showTrigger: new TimestampTrigger(timestamp) })
registration.getNotifications({ includeTriggered: true })
```

两种形式只存在于开启了 `chrome://flags/#enable-experimental-web-platform-features` 的 Chromium 中（[Notification Triggers](https://developer.chrome.com/docs/web-platform/notification-triggers)，developer.chrome.com）。该特性在 Chrome Platform Status 上的状态为「In developer trial (Behind a flag)」（[chromestatus.com](https://chromestatus.com/feature/5133150283890688)）；Chrome 为它运行过的 origin trial 之后没有正式发布。

## 参数

| 参数 | 类型 | 含义 |
|---|---|---|
| `showTrigger` | `TimestampTrigger` | 显示通知的时刻。构造函数接受以毫秒计的 `DOMTimeStamp`，可通过 `trigger.timestamp` 读回。过去的时间立即显示。 |
| `includeTriggered` | boolean，`getNotifications()` 的选项 | 把尚未显示的已安排通知也包含进来，以便页面列出或用 `notification.close()` 取消它们。默认 `false`。 |

提案还讨论过为被取消的触发器触发 `notificationclose`，以及对触发时刻能提前多远设限；两者都未写入规范。

## 异常

无。

## 平台可用性

没有浏览器发布该选项。Chromium 以上述状态把实现留在实验性特性标志之后；Firefox 和 WebKit 没有实现，MDN 对 `showNotification()` 的参考列出 `actions`、`badge`、`body`、`data`、`dir`、`icon`、`image`、`lang`、`navigate`、`renotify`、`requireInteraction`、`silent`、`tag`、`timestamp` 与 `vibrate`，其中没有 `showTrigger`。公开的停止原因是无法跨平台提供一致、可靠的行为，这与限制[周期性后台同步](/zh/reference/notifications/periodic-background-sync/)的是同一个约束。

## 示例

前两个示例在开启标志后运行；第三个是唯一属于生产代码的。

### 在标志之后安排一条提醒

开启标志后，触发器只是多出来的一个选项。`tag` 让后续调用替换已安排的通知，而不是再加一条。

```js
async function scheduleReminder(registration, when, title) {
  await registration.showNotification(title, {
    tag: `reminder-${when}`,
    body: '10 分钟后开始',
    showTrigger: new TimestampTrigger(when - 10 * 60 * 1000),
  });
}
```

调用时除了存下请求什么都不发生；即使浏览器在此期间被关闭，通知仍在触发时刻出现，这正是任何已发布 API 都不具备的特性。

### 取消已安排的通知

`getNotifications({ includeTriggered: true })` 把已安排的条目和已显示的一并返回；在触发之前关闭其中一条就是取消。

```js
async function cancelReminder(registration, when) {
  const pending = await registration.getNotifications({ includeTriggered: true });
  for (const notification of pending) {
    if (notification.tag === `reminder-${when}`) notification.close();
  }
}
```

没有标志时选项对象被忽略，`pending` 只包含已显示的通知，循环找不到可取消的条目。

### 检测该选项并退回服务端调度

测试方法是 `'showTrigger' in Notification.prototype`，在所有正式发布的浏览器里都是 `false`。兜底是唯一的生产路径：把计划存在服务端，到时候用 Web Push 投递。

```js
async function remindAt(registration, when, title) {
  if ('showTrigger' in Notification.prototype) {
    return registration.showNotification(title, { showTrigger: new TimestampTrigger(when) });
  }
  // 不开标志的浏览器都不支持：在服务端调度，用 Web Push 投递
  await fetch('/api/reminders', { method: 'POST', body: JSON.stringify({ when, title }) });
}
```

服务端路径依赖投递时刻的网络连接，这正是提案想要消除的限制，也是它仍不时被人提起的原因。

:::observed
在未开启实验性标志的普通 Chrome 配置中，`'showTrigger' in Notification.prototype` 返回 `false`，`typeof TimestampTrigger` 返回 `"undefined"`；向 `showNotification()` 传入 `showTrigger` 会被静默忽略，因为未知的字典成员会被丢弃，通知立即显示。把 `chrome://flags/#enable-experimental-web-platform-features` 设为 Enabled 并重启浏览器后，两个检查都翻转，此时页面触及的正是 Platform Status 条目上「In developer trial (Behind a flag)」的状态（[chromestatus.com](https://chromestatus.com/feature/5133150283890688)）。
:::

## 另请参阅

- [Notification Triggers](https://developer.chrome.com/docs/web-platform/notification-triggers)（developer.chrome.com）
- [Notification Triggers explainer](https://github.com/beverloo/notification-triggers)（github.com）
- [Chrome Platform Status: Notification Triggers](https://chromestatus.com/feature/5133150283890688)（chromestatus.com）
- [Web Push 与 PushManager.subscribe()](/zh/reference/notifications/web-push/)
- [用于内容更新的周期性后台同步](/zh/reference/notifications/periodic-background-sync/)
- [Notifications API](/zh/reference/notifications/notifications-api/)