Budget API 简介

借助 Push Messaging API,即使浏览器处于关闭状态,我们也可以向用户发送通知。许多开发者希望能够在不打开浏览器的情况下使用此消息功能来更新和同步内容,但该 API 有一个重要的限制:您必须始终针对收到的每一条推送消息显示一条通知。

能够发送推送消息以同步用户设备上的数据或隐藏您之前显示的通知对用户和开发者来说非常有用,但允许 Web 应用在用户不知情的情况下在后台执行工作可能会被滥用。

Budget API 是一个新 API,旨在让开发者在不通知用户的情况下执行有限的后台工作,例如静默推送或执行后台提取。在 Chrome 60 及更高版本中,您将能够开始使用此 API,Chrome 团队非常期待收到开发者的反馈。

为了让开发者能够在后台使用用户的资源,Web 平台将引入使用新版 Budget API 的预算概念。每个网站都会根据用户互动度获得资源奖励,供其用于后台操作(如静默推送,其中每次操作都会耗尽预算)。当预算用尽后,系统将不再在用户不知情的情况下执行后台操作。用户代理将负责根据其启发词语确定分配给 Web 应用的预算,例如,预算配额可以与用户互动度相关联。每个浏览器都可以自行决定自己的启发词语。

TL;DRBudget API 可让您预留预算、使用预算、获取剩余预算列表以及了解后台操作的费用

预留预算

在 Chrome 60 及更高版本中,无需任何标志即可使用 navigator.budget.reserve() 方法。

借助 reserve() 方法,您可以为特定操作请求预算,该方法会返回一个布尔值,用于指示是否可以预留预算。如果预留了预算,则无需通知用户您的后台工作。

在推送通知示例中,您可以尝试为“静默推送”操作预留预算,如果 reserve() 解析为 true,则允许执行该操作。否则,它将返回 false,并且您需要显示通知

self.addEventListener('push', event => {
 const promiseChain = navigator.budget.reserve('silent-push')
   .then((reserved) => {
     if (reserved) {
       // No need to show a notification.
       return;
     }

     // Not enough budget is available, must show a notification.
     return registration.showNotification(...);
   });
 event.waitUntil(promiseChain);
});

在 Chrome 60 中,“silent-push”是唯一可用的操作类型,但您可以在规范中找到操作类型的完整列表。此外,一旦使用完预算,就无法轻松增加预算以进行测试或调试,但您可以在 Chrome 中创建新的配置文件作为临时解决方法。遗憾的是,您也无法使用无痕模式来执行此操作,因为 Budget API 在无痕模式下会返回零预算(不过,在测试期间,有一个bug 会导致错误)。

仅当您打算在未来某个时间点执行自己预留的操作时,才应调用 reserve()。请注意,如果您在上述示例中调用了 reserve,但仍显示了通知,则系统仍会使用相应预算。

reserve() 无法单独实现的一个常见用例是,能够从后端安排静默推送。Budget API 确实提供了一些 API 来实现此用例,但这些 API 仍在 Chrome 中开发中,目前仅在标志和 / 或源试用后面提供。

Budget API 和源试用

Web 应用可以使用两种方法(getBudget()getCost())来规划其预算的使用。

在 Chrome 60 中,如果您注册了源试用,则可以使用这两种方法,但如果您要进行测试,则可以通过启用“实验性 Web 平台功能”标志在本地使用它们(在 Chrome 中打开 chrome://flags/#enable-experimental-web-platform-features)。

我们来看看如何使用这些 API。

获取预算

您可以使用 getBudget() 方法查找可用预算。某些浏览器(例如 Chrome)的预算会随时间推移而“递减”,因此为了让您能够全面了解预算情况,此方法会返回一个 BudgetStates 数组,指明未来各个时间点的预算。

如需列出预算条目,我们可以运行以下命令:

navigator.budget.getBudget()
.then((budgets) => {
  budgets.forEach((element) => {
    console.log(\`At '${new Date(element.time).toString()}' \` +
      \`your budget will be '${element.budgetAt}'.\`);
  });
});

第一个条目是您当前的预算,其他值将显示未来各个时间点的预算。

At 'Mon Jun 05 2017 12:47:20' you will have a budget of '3'.
At 'Fri Jun 09 2017 10:42:57' you will have a budget of '2'.
At 'Fri Jun 09 2017 12:31:09' you will have a budget of '1'.

添加未来预算配额的好处之一是,开发者可以与其后端共享此信息,以调整其服务器端行为(即仅在客户端有静默推送预算时发送推送消息以触发更新)。

获取操作费用

为了确定某项操作的费用是多少,调用 getCost() 将返回一个数字,表示如果您针对该操作调用 reserve() 将消耗的最高预算金额。

例如,我们可以通过以下代码了解在收到推送消息时不显示通知的费用(即静默推送的费用):

navigator.budget.getCost('silent-push')
.then((cost) => {
  console.log('Cost of silent push is:', cost);
})
.catch((err) => {
  console.error('Unable to get cost:', err);
});

在撰写本文时,Chrome 60 将会输出以下内容:

Cost of silent push is: 2

关于 reserve()getCost() 方法,需要强调一点是,操作的实际费用可以低于 getCost() 返回的费用。如果您的当前预算低于所示费用,您可能仍可以预订操作。规范中的具体详情如下

这是 Chrome 中当前使用的 API。随着 Web 继续支持需要执行后台工作(例如后台提取)的新 API,您可以使用 Budget API 来管理您可以执行的操作数量,而无需通知用户。

在使用该 API 时,请在 GitHub 代码库中提供反馈,或在 crbug.com 上提交 Chrome bug。