ManifestV3 新承诺错误:消息端口在收到响应之前关闭

Cha*_*son 8 javascript google-chrome-extension chrome-extension-manifest-v3

我正在开发一个扩展,它在其内容脚本和后台服务工作人员(清单 V3)之间进行大量消息传递,并且我注意到新的基于 Promise 的 V3 API 存在一个奇怪的问题,特别是 sendResponse () 功能。

对于需要响应的 API 调用,一切正常。但是,如果我不需要响应并且不提供回调函数或使用 Promise 的 .then() 方法(或 async/await),则会引发 Promise 错误 - 它表示“消息端口在响应之前关闭”已收到。”

奇怪的是,调用仍然有效,所以我猜这个错误更像是一个警告。

代码示例:

在内容脚本中,向后台发送消息:

chrome.runtime.sendMessage({ type: 'toggle_setting' })
Run Code Online (Sandbox Code Playgroud)

后台脚本获取消息并执行某些操作,然后退出而不发送响应:

chrome.runtime.onMessage.addListener( (message, sender, sendResponse) => {
  if (message.type === 'toggle-setting') {
    //* do whatever it does
  }
})
Run Code Online (Sandbox Code Playgroud)

该后台代码是引发上述错误的原因。但是,如果我向其中添加一行并调用不带参数的 sendResponse() 函数,则不会发生错误。

chrome.runtime.onMessage.addListener( (message, sender, sendResponse) => {
  sendResponse()
  if (message.type === 'toggle-setting') {
    //* do whatever it does
  }
})
Run Code Online (Sandbox Code Playgroud)

因此,这消除了错误消息,但我不太清楚为什么在不需要或不需要响应时有必要这样做。是否有其他方法可以向基于 Promise 的 V3 API 发出信号,或者现在是否有必要调用 sendResponse(),即使您不需要?

wOx*_*xOm 12

这是Chrome 99-101 中的一个错误,在 Chrome 102 中修复。

原因是 sendMessage 现在在内部被 Promise 化了,所以我们可以await这样做,但副产品是,当我们自己不指定回调时,它会在内部添加,以便调用返回 Promise,这意味着因为我们不要在onMessage中调用sendResponse,API会认为是我们错误地使用了回调而没有提供响应,并如此报告。

解决方法 1:在 chrome.runtime.onMessage 中调用 sendResponse()

解决方法 2:抑制此特定错误

还可以在调用之前修补 API 固有的缺乏调用堆栈的问题。

// sender (in the question it's the content script)
sendMessage('foo');

// sendMessage('foo').then(res => whatever(res));
// await sendMessage('foo');

function sendMessage(msg) {
  const err1 = new Error('Callstack before sendMessage:');
  return new Promise((resolve, reject) => {
    chrome.runtime.sendMessage(msg, res => {
      let err2 = chrome.runtime.lastError;
      if (!err2 || err2.message.startsWith('The message port closed before')) {
        resolve(res);
      } else {
        err2 = new Error(err2.message);
        err2.stack += err1.stack.replace(/^Error:\s*/, '');
        reject(err2);
      }
    });
  });
}
Run Code Online (Sandbox Code Playgroud)