Chrome 带有 SVG 图标的扩展 (chrome.browserAction.setIcon)

Chrome extension with SVG icons (chrome.browserAction.setIcon)

我在 Chrome 扩展程序中使用可缩放 SVG 图标。

chrome.browserAction.setIcon({
  tabId: tabId,
  path: '../icons/' + icon + '/scalable.svg'
});

我想根据一些参数来切换图标,所以我有视觉反馈。

我意识到,当我快速切换图标时,Chrome 搞砸了,我经常看到错误的图标。我在代码中添加了 console.log 打印以确保我正确切换图标并且我发现我的代码没有错误。

看起来 Chrome 异步执行此类图标更改请求,并且 SVG 到像素的转换有时比平时花费更长的时间。这会导致执行顺序错误。

例如,如果我将图标从 A 切换到 B,然后切换到 C ;然后到 D,...最后我可能会看到 C,尽管最后的更改请求是将其切换为 D.

关于如何解决这个烦人的问题有什么想法吗?

  1. 使用 Promise
  2. 将调用链接到 API
  3. 如果您经常调用setIcon,请自己创建一个imageData缓存并使用它而不是path,因为API每次都会重新读取源图标并重新创建imageData.

这是一个通用示例,未经测试:

const queue = {};
const cache = {};
// auto-clean the queue so it doesn't grow infinitely
chrome.tabs.onRemoved.addListener(tabId => delete queue[tabId]);

async function setIcon(tabId, icon) {
  const url = '../icons/' + icon + '/scalable.svg';
  const imageData = await (cache[url] || (cache[url] = loadImageData(url)));
  queue[tabId] = (queue[tabId] || Promise.resolve()).then(() =>
    new Promise(resolve =>
      chrome.browserAction.setIcon({tabId, imageData}, resolve)));
}

function loadImageData(url) {
  return new Promise((resolve, reject) => {
    const data = {};
    const img = new Image();
    img.src = url;
    img.onload = () => {
      for (const size of [16, 32]) {
        const canvas = document.createElement('canvas');
        document.documentElement.appendChild(canvas);
        canvas.width = canvas.height = size;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0);
        data[size] = ctx.getImageData(0, 0, size, size);
        canvas.remove();
      }
      resolve(data);
    };
    img.onerror = reject;
  });
}