【问题标题】:Chrome Extension - priority messagingChrome 扩展程序 - 优先消息
【发布时间】:2019-01-04 16:26:55
【问题描述】:

我正在开发一个 chrome 扩展程序,它使用 chrome 的运行时 sendMessage API 在扩展程序和内容脚本注入的页面之间来回发送一次性消息。问题是我需要一些消息在这个系统中优先。我已经实现了一个自定义端口来执行优先级消息传递,但是我似乎无法使用端口解决方案复制 sendResponse API。

流程

客户端调用一个返回一个promise的方法,该方法为request和resolve方法存储一个nonce,通过parent.postMessage({data}, '*')向它的父级发送一条消息,然后在windowsmessage监听器被调用时解析它包含相同随机数的数据。

扩展的内容脚本监听消息:

const port = chrome.runtime.connect({name: 'priorityPort'})
function getResponse(data) {
  return new Promise((resolve, reject) => {
    if (priority) {
      port.postMessage({data})
      port.onMessage.addListener(msg => {
        resolve(msg)
      })
    } else {
      chrome.runtime.sendMessage({data}, resolve)
    }
  })
}

window.addEventListener('message', async event => {
  const response = await getResponse(event.data)
  event.source.postMessage({response})
})

然后后台页面充当连接的另一端

// normal
chrome.runtime.onMessage.addListener((obj, sender, sendResponse: data => {
  ;(async () => {
    sendResponse({ status: 'success', body })
  })()
  return true
})
// priority
chrome.runtime.onConnect.addListener((port) => {
  ;(async () => {
    port.onMessage.addListener(async msg => {
      port.postMessage({ status: 'successs', body })
    })
  })()
  return true
})

但是,这不会像sendResponse 那样将响应返回给请求者。任何帮助是极大的赞赏。

【问题讨论】:

  • 每次发送优先级消息时,您都会添加一个新的端口侦听器,这会使之前的所有侦听器触发新消息,它还会泄漏内存,并可能导致您观察到的问题。顺便说一句,在 onConnect 监听器中不需要“返回 true”,因为它没有 sendResponse 参数。
  • 你可能已经把它弄得更复杂了。您可以使用长期连接(端口连接)来完成所有这些操作。
  • @Titus 当然,但我在问如何通过长期连接实现sendResponse 功能

标签: javascript google-chrome google-chrome-extension


【解决方案1】:

您可以创建一个队列,如下所示:

class Queue {
 constructor() {
   this.arr = [];
   this.awaiting = [];
 }

 enqueue(msg) {
   if (this.awaiting.length) {
     this.awaiting.shift()(msg)
   }else {
     this.arr.push(msg)
   }
 }
   
 dequeue() {
   if (this.arr.length) {
     return this.arr.shift()
   }
   return new Promise(resolve => {
     this.awaiting.push(resolve);
   }); 
 }
}

这是你如何使用它的:

const queue = new Queue();
const port = chrome.runtime.connect({name: 'priorityPort'})

port.onMessage.addListener(msg => {
  queue.enqueue(msg);
})


window.addEventListener('message', async event => {
  port.postMessage({date: event.data})
  const response = await queue.dequeue()
  event.source.postMessage({response})
})

您可以开发某种通信协议并拥有多个队列来处理不同类型的消息。在端口的消息监听器中,检查消息的类型并将其添加到相应的队列中。

这只是一个想法,我不确定你到底想要做什么,我可能已经为你的用例做了这种复杂的事情。

【讨论】:

  • 这实际上是有见地和有趣的。谢谢
  • @bdeo 我稍微改了一下,Queue 有一个缺陷。起初我以为您的问题有一个简单的解决方案,但后来我意识到在这种情况下端口的消息侦听器是一个问题。