chrome 扩展 - sendResponse 不等待异步功能

IT技术 javascript google-chrome-extension
2021-01-31 03:28:18

我有一个异步问题(我相信)。sendResponse()contentscript.js中不等待getThumbnails()返回。

popup.js 中发送消息

chrome.tabs.sendMessage(tabs[0].id, {message: "get_thumbnails", tabUrl: tabs[0].url},
      function (respThumbnails) {
            const thumbUrl = respThumbnails.payload;
            console.log("payload", thumbUrl)   
      }
);

然后,在contentscript.js这条消息:

chrome.runtime.onMessage.addListener(async function(request,sender,sendResponse) {
    if(request.message === "get_thumbnails") {
        const payload = await getThumbnails();
        console.log("thumbPayload after function:", payload)
        sendResponse({payload:payload});   
    }
});


async function getThumbnails() {
    let tUrl = null;
    var potentialLocations = [
        {sel: "meta[property='og:image:secure_url']",   attr: "content" },
        {sel: "meta[property='og:image']",              attr: "content" },
    ];

    for(s of potentialLocations) {
        if(tUrl) return
        const el = document.querySelector(s.sel);
        if(el) {
            tUrl = el.getAttribute(s.attr) || null;
        } 
    }
    return tUrl;
};

但也有可能问题出在我的getThumnails()函数上,因为在大多数情况下,payload 是 null而不是 undefined。所以getThumbnails()可能会在它完全执行之前返回。如果是这样的话,我不知道为什么......

我也试过这个代码getThubnails()

async function getThumbnails() {
  let x = await function() {
    let tUrl = null;
    var potentialLocations = [
        {sel: "meta[property='og:image:secure_url']",   attr: "content" },
        {sel: "meta[property='og:image']",              attr: "content" },
    ];

    for(s of potentialLocations) {
        if(tUrl) return
        const el = document.querySelector(s.sel);
        if(el) {
            tUrl = el.getAttribute(s.attr) || null;
        } 
    }
    return tUrl;
  }
  return x;
};

但这不起作用,它似乎破坏了我的代码......

1个回答

onMessage 的回调应该返回一个文字 true值(文档),以保持内部消息通道打开,以便 sendResponse 可以异步工作。

问题是,您的回调是用async关键字声明的,这意味着它返回 aPromise因此它不能返回文字true值。Chrome 扩展 API 不支持回调的返回值中的 Promise,因此它被忽略。

使用标准函数回调和嵌套的异步 IIFE:

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.message === "get_thumbnails") {
    (async () => {
      const payload = await getThumbnails();
      console.log("thumbPayload after function:", payload)
      sendResponse({payload});
    })();
    return true; // keep the messaging channel open for sendResponse
  }
});
我在弹出窗口和浏览器操作菜单中有相同的代码,在持久性背景页面中有一个 onMessage 处理程序。奇怪的是,在使处理程序异步后,弹出窗口运行良好。直到回去测试菜单后,我才意识到有些东西坏了。如果弹出窗口也没有打开,则菜单工作正常。但是,如果是,则等待从菜单对后台进行的异步调用从未收到响应。打开两页(和两个端口)似乎打破了它。将等待从处理程序中移出固定的东西。
2021-03-24 03:28:18
当您编辑内容脚本时,您需要在 chrome://extensions 页面上重新加载扩展程序,并重新加载运行该内容脚本的网页。至于那个功能,我根本看不到任何需要asyncawait内部的东西
2021-03-25 03:28:18
感谢您的回答。但是,我已尝试使用您的代码,但仍然无法正常工作。它返回空值。我的 getThumbnails() 函数一切正常吗?除了等待 document.querySelector,我删除了 :)
2021-03-30 03:28:18
iframe 问题是一个不同的问题。在我看来,您可以简单地在弹出窗口中添加一个 runtime.onMessage 侦听器,并在您的内容脚本中使用 runtime.sendMessage 而不是 sendResponse。或者您可以切换到 tabs.executeScript 而不是带有消息的声明内容脚本,因此您将收集一个数组中所有帧的输出。
2021-04-05 03:28:18
是的,当然,我重新加载扩展程序并一直刷新页面。您的代码实际上正在运行,但我仍然遇到问题的原因是我所在的页面有 6 或 7 个框架。由于我的清单中有“all_frames”=true,因此每个帧都会发送一条新消息,并且所有这些消息都向我的 popup.js 发送响应,但是 popup.js 仅收到 1 个响应,甚至发送了 6 个。 . 我不知道我是否清楚,但例如,我在我的内容脚本中执行 console.log("location:", document.location) ,它控制台记录了 6 个不同的位置......我找不到解决方案..
2021-04-06 03:28:18