Using promises(使用)
随着 Manifest V3 的引入,许多扩展 API 方法现在返回承诺。本文档解释了如何使用 Promise。
关键术语
promise 是一个 JavaScript 对象,表示异步操作的最终结果。有关 Promise 及其使用的更多信息,请参阅有关使用 Promise 的 MDN 文档promises。
# Introduction(介绍)
Promise 在 ES6 规范中包含后不久就被引入到 Chrome 中。它们是现代 JavaScript 的一个重要特性,具有以下优点:
- 简化的错误处理
- 以同步方式编码以调用异步函数
- 调用并发函数的简单“
fork and join
”语法
在 Manifest V2 扩展程序开发人员可以使用库来“承诺(promisify)”Chrome 的扩展程序 API。随着 Manifest V3 的引入,Chrome 的许多扩展 API 现在可以返回promises。Chrome 团队还在逐步为其他 API 添加 promise 支持。
提示 Manifest V2 下的扩展 API 不会返回 Promise,并且尚未在 Manifest V3 中的所有方法上都可用。
Promise 可以而且应该在许多情况下使用。但是,有时(例如,事件侦听器)Promise不起作用而回调更合适。支持承诺(Promise)的方法也支持回调以提供向后兼容性。
# Can I use promises?
您可以并且应该在扩展代码中使用承诺(promises),其中承诺(promise)可用且适用于用例。
并非扩展 API 中的所有方法都支持承诺(promises)。有时那是因为我们还没有在方法上添加 promise 支持;在许多情况下,这是因为使用承诺(promise)对于该方法不可行。
您可以通过检查其 API 参考页面来检查方法是否支持 promise:
示例方法 captureVisibleTab()
可以在 chrome.tabs
API 中找到。此方法支持承诺,因为该方法的签名之一返回一个Promise
。为了使这一点更容易一目了然,参考文档还在签名下方显示了一个 Promise 。
# How to use promises(如何使用承诺)
在很多地方使用 Promise 会产生更干净、更易于维护的代码。您应该考虑在以下情况下使用 promise:
- 任何时候您想通过使用更“同步(synchronous)”的调用样式来清理您的代码。
- 使用回调处理错误太困难的地方。
- 当您想要一种更简洁的方式来调用多个并发方法并将结果收集到单个代码线程中时。
# Converting a callback to a promise(将回调转换为承诺)
了解如何在扩展 API 中使用 promise 的一种方法是比较两个等效的代码片段,一个使用回调,一个使用 promise。以下示例显示了这种比较:
# Standard callback implementation(标准回调实现)
function openTabOnRight(onComplete) {
chrome.tabs.query(queryOptions, function(tabs) {
if (chrome.runtime.lastError) {
onComplete({error: chrome.runtime.lastError});
return;
}
if (!tabs.length) {
onComplete();
return;
};
chrome.tabs.create({
url: 'https://example.com',
index: tab[0].index + 1,
}, function(tab) {
if (chrome.runtime.lastError) {
onComplete({error: chrome.runtime.lastError});
}
console.log('tab created', tab);
onComplete(tab);
});
});
}
# Promise implementation(承诺实现)
// 此示例没有显式错误处理程序,因为错误
// 自动沿承诺(Promise)链向下传播。
function openTabOnRight() {
return chrome.tabs.query(queryOptions)
.then((tabs) => {
if (!tabs.length) return;
return chrome.tabs.create({
url: 'https://example.com',
index: tab[0].index + 1,
});
})
.then(tab => {
if (!tab) return;
console.log('tab created', tab);
return tab;
});
}
# Error handling(错误处理)
根据扩展是使用回调还是承诺(promise),返回错误的工作方式不同。
# Error handling with callbacks(使用回调处理错误)
如果使用回调,则在回调执行期间设置 chrome.runtime.lastError
。它不会作为 JS 错误抛出(这会中断 JS 执行),并且不会在回调运行的持续时间之外设置(这将导致它在其他执行期间“随机”设置)。扩展程序会像这样查看最后一个错误:
chrome.tabs.create({...}, (result) => {
if (chrome.runtime.lastError) {
// Handle last error
}
});
# Error handling with promises(使用 promise 处理错误)
Promise 旨在提供异步结果,包括成功和失败。承诺(promise)失败(承诺(promise)拒绝)的处理方式不同。它可能看起来像这样:
chrome.tabs.create({...})
.then((result) => {
// success case
})
.catch((error) => {
// failure case
});
使用 Promise 时,扩展 API 不会设置 chrome.runtime.lastError
;相反,它们将错误作为参数提供给.catch()
中的函数。
在具有单个承诺的更简单的情况下,您可以将错误处理程序作为第二个参数提供给
.then()
,而不是链接到.catch()
。有关此主题的更多信息,请参阅有关链式承诺的 MDN 文章,MDN article on chained promises。
无论您是使用 .catch()
还是 .then()
的可选第二个参数接收错误,这种错误处理形式都可以帮助您以更同步的方式编写异步逻辑。
# Using async/await(使用异步/等待)
JavaScript 还提供了 async/await 作为 Promise 之上的语法糖,让您以更命令式的方式进行编码。以下示例显示了如何使用 async/await 实现前面显示example shown earlier的示例:
// Async/await implementation
async function openTabOnRight() {
//// 当不包含在 try/catch 中时,异步抛出错误
// 函数将沿着承诺链向下传播
let tabs = await chrome.tabs.query(queryOptions);
if (!tabs.length) return;
let tab = await chrome.tabs.create({
url: 'https://example.com',
index: tab[0].index + 1,
});
if (!tab) return;
console.log('tab created', tab);
return tab;
}
请注意,
await
仅在异步函数和模块的顶级主体中有效。您可以通过在扩展清单manifest的“background”
键中设置“type”:“module”
来将后台服务工作者加载为模块。
By.一粒技术服务.