【问题标题】:Messaging inside Chrome Extension in ClojureScriptClojureScript 中 Chrome 扩展程序中的消息传递
【发布时间】:2015-12-19 09:00:57
【问题描述】:

我正在尝试编写一个 Chrome 扩展程序,在内容脚本和后台页面之间进行一些基本的通信。

在 Javascript 中,我会在内容页面和后台页面中注册监听器,例如在后台页面中:

chrome.browserAction.onClicked.addListener(function(tab) {
  // Send a message to the active tab
  chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    var activeTab = tabs[0];
    chrome.tabs.sendMessage(activeTab.id, {"message": "clicked_browser_action"});
  });
});

(取自this tutorial)。

另一个适用于 Javascript 的示例:

// content.js
chrome.runtime.sendMessage({screenShot: true}, function(response) {
  console.log("response: " + response);
});

// background.js
chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    alert('message received!');
    console.log("request: " + request);
    if (request.screenShot) {
      // do something
    }
});

如何将上述代码翻译成 ClojureScript?

我的第一次尝试是基于lein-chrome-extension模板创建一个项目,并使用Khromaruntime/connect方法依赖于core-async。但是我在content.cljsbackground.cljs 脚本之间没有得到适当的沟通。在content.cljs 我有:

(defn init []
  (go
    (let [bg (runtime/connect)]
      (console/log "content script test")
      (while true
        (>! bg :lol-i-am-a-content-script)
        (console/log "Background said: " (<! bg))))))

background.cljs:

(defn on-connect-listener []
  (console/log "on-connect-listener")
  (go-loop 
    [channel (runtime/on-connect)]
    (let [content (<! channel)]
      (console/log "Content script said: " (<! content))
      (>! content :fml-i-am-the-background-script)
      (recur channel))))

(定义初始化 [] (on-connect-listener))

在 Chrome 控制台中,我只收到“后台说:fml-i-am-the-background-script”消息,因此只有后台发送到内容页面的消息,反之亦然(我本来希望“内容脚本说:lol-i-am-a-content-script")。

很可能我在这里犯了一些明显的错误。有人可以帮忙吗?

谢谢!

【问题讨论】:

  • 你能展示任何尝试以及它们是如何失败的吗?
  • @Xan - 扩展了我原来的问题。谢谢!

标签: google-chrome-extension clojurescript


【解决方案1】:

两周前,我开始在 ClojureScript 中开发一个 chrome 扩展。我开始使用 Khroma 并且使用他们的库在我的背景页面和内容脚本(或我的背景页面和弹出按钮页面)之间实现双向通信没有问题。所以我可以确认图书馆工作。不幸的是,我在这里的代码示例中没有看到任何明显的错误。

附带说明:我不喜欢 Khorma 如何“滥用” code.async 通道来实现双工通信。 Khroma 在连接时为您提供类似通道的对象。通过在其上放置消息,您发送消息,并通过从中获取消息,您等待接收消息。简单的?但这并不是真正的 core.async 通道合约。通常在 core.async 中,放置和接收操作在同一个队列上进行,并且可以由任何人(生产者或消费者)完成。 Khroma 有效地将其变成了一个内部有两个队列的“通道”。一个用于发送,一个用于接收。如果您将某些内容放在频道上,则无法将其收回(例如)。起初这让我很困惑。而且我认为它也让你感到困惑,这样的代码很难阅读:

(let [content (<! channel)]
      (console/log "Content script said: " (<! content))
      (>! content :fml-i-am-the-background-script))

问题是>!它从不阻塞(在 Khroma 的情况下,put 意味着发送,这是一个非阻塞函数调用,与通道无关)。但是

所以我决定编写自己的库来替换 Khroma。不仅是为了修复这个小的设计缺陷,而且主要是因为我想从铬源自动生成库,所以它自动涵盖了所有 API。

该库名为 Chromex,我刚刚发布了一个简单的 Chrome 扩展示例项目以及一些文档:https://github.com/binaryage/chromex-sample

后台页面的代码如下所示: https://github.com/binaryage/chromex-sample#background-page

请注意,我还将runtime.Port 包装为类似core.async 的通道,但我不假装双向通信。你只能拿!从通道接收消息(通道包装器仅实现 core-async/ReadPort 协议)。要发布消息,您必须使用单独的post-message! 协议方法。

【讨论】:

  • 感谢您的回答。我正在研究你的例子。
猜你喜欢
  • 1970-01-01
  • 2012-09-28
  • 1970-01-01
  • 2011-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-27
  • 1970-01-01
相关资源
最近更新 更多