chrome扩展-sendResponse不等待异步功能[重复]

Posted

技术标签:

【中文标题】chrome扩展-sendResponse不等待异步功能[重复]【英文标题】:chrome extension - sendResponse not waiting for async function [duplicate] 【发布时间】:2022-01-22 22:21:24 【问题描述】:

我遇到了异步问题(我相信)。 contentscript.js 中的sendResponse() 不会等待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() 函数,因为大多数时候,有效负载为空,而不是未定义。所以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;
;

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

【问题讨论】:

顺便说一句,document.querySelector 没有返回 Promise,所以等待它没有意义。 【参考方案1】:

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

问题是,你的回调是用 async 关键字声明的,这意味着它返回一个 Promise 所以它不能返回一个文字 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
  
);

【讨论】:

感谢您的回答。但是,我已尝试使用您的代码,但仍然无法正常工作。它返回空值。我的 getThumbnails() 函数一切正常吗?在我删除的 await document.querySelector 旁边:) 当您编辑内容脚本时,您需要在 chrome://extensions 页面上重新加载扩展,并重新加载运行该内容脚本的网页。至于那个功能,我根本看不到里面有任何需要asyncawait的东西。 是的,当然,我一直在重新加载扩展并刷新页面。您的代码实际上正在运行,但我仍然遇到问题的原因是因为我所在的页面有 6 或 7 帧。因为我的清单中有“all_frames”=true,所以会为每个帧发送一条新消息,并且它们都发送响应到我的 popup.js,但 popup.js 只收到 1 个响应,甚至发送了 6 个艰难的响应。 . 我不知道我是否清楚,但例如,我在我的内容脚本中执行 console.log("location:", document.location) ,它控制台记录 6 个不同的位置......我找不到解决方案.. iframe 问题是另一个问题。在我的脑海中,您可以简单地在弹出窗口中添加一个 runtime.onMessage 侦听器,并在您的内容脚本中使用 runtime.sendMessage 而不是 sendResponse。或者,您可以切换到 tabs.executeScript,而不是使用消息传递声明的内容脚本,这样您就可以将所有帧的输出收集到一个数组中。 我在弹出窗口和浏览器操作菜单中有相同的代码,在持久背景页面中有一个 onMessage 处理程序。奇怪的是,在使处理程序异步后,弹出窗口工作得很好。只是在回去测试菜单后,我才意识到有些东西坏了。如果弹出窗口也没有打开,则菜单工作正常。但如果是这样,从菜单发出的对后台的等待异步调用永远不会收到响应。打开两个页面(和两个端口)似乎打破了它。将等待从处理程序中移出修复了问题。

以上是关于chrome扩展-sendResponse不等待异步功能[重复]的主要内容,如果未能解决你的问题,请参考以下文章

Chrome 扩展中的持久服务工作者

BluetoothGattServer.sendResponse 中的数据长度不能超过 20 字节。 (低功耗蓝牙)

Chrome 扩展将 jquery 注入 iframe

致命异常:NSInternalInconsistencyException 此请求已被绝育 - 您不能调用 -sendResponse: 两次,也不能在编码后调用

rpc sendResponse panic:reflect: 在 ptr 上调用 reflect.Value.Int

谷歌Chrome扩展计时器重置