chrome.runtime是否支持使用可传输对象发布消息?

Sea*_*son 7 javascript google-chrome-extension transferable

我正在学习可转移对象:http://updates.html5rocks.com/2011/12/Transferable-Objects-Lightning-Fast

它们看起来非常棒,我想在我的扩展中使用它们来加速将数据从iframe内部传递到iframe之外.

我有这个示例代码工作,但它使用Web Worker:

var s = document.createElement("script");
s.type = "text/js-worker";
s.innerHTML = 'console.log("i ran!");';
document.body.appendChild(s);

var blob = new Blob(Array.prototype.map.call(document.querySelectorAll("script[type=\"text\/js-worker\"]"), function (oScript) {
    return oScript.textContent;
}), { type: "text/javascript" });

var worker = new Worker(window.URL.createObjectURL(blob));

var arrayBuffer = new ArrayBuffer(1);

worker.onmessage = function (oEvent) {
    console.log("Called back by the worker!\n");
};

console.log("worker:", worker);
worker.postMessage(arrayBuffer, [arrayBuffer]);

if (arrayBuffer.byteLength) {
    console.error("nope");
} else {
    console.log("it worked");
}
Run Code Online (Sandbox Code Playgroud)

有没有人有任何关于支持的信息,或支持使用端口的crbug的时间表,如:

var port = chrome.runtime.connect({
    name: 'youTubeIFrameConnectRequest'
});

//port.postMessage -- transferrable object.
Run Code Online (Sandbox Code Playgroud)

我没有看到任何支持它或支持它的任何东西,但这似乎很奇怪!

Rob*_*b W 13

通过扩展消息传递API的消息始终是JSON序列化的.此格式不仅用于在后台页面和内容脚本之间传递消息,还用于本机应用程序.所以,我想传递API的消息不太可能支持更多项目.

2012年已经请求了结构化克隆算法(比JSON序列化更强大,比转换功能更强大)(Chromium issue 112163).这个问题仍然存在; 有人建议使用SharedWorker"蹦床".

SharedWorker由相同的起源政策的影响,因此呼叫者需要驻留在相同的起源.为此,您可以添加页面web_accessible_resources,并将此页面嵌入到框架中.

在这个答案的最后,我附上了一个蹦床的简单实现.使用这些文件创建扩展.然后,打开一个标签.此选项卡将包含嵌入式框架,演示将向共享工作程序发送消息.此消息将被传输到后台页面,只需查看后台页面的控制台即可查看这些消息.
演示很少,您需要自己实现端口管理(销毁).
该演示不使用可传递的消息传递(但),因为它是允许多个端口的一般实现.如果您确保最多同时存在两个端口,那么您可以更改代码以使用transferables(只有在收到一个发送者和一个发送者时,transferables才有意义,因为对象的所有权也被转移).

特例:同一过程

如果您的所有代码都在同一个进程中运行,那么您可以使用更简单的方法而不使用SharedWorkers.

相同的原始策略禁止从/向框架和扩展的直接访问,因此您将使用parent.postMessage跨越此桥.然后,在页面的onmessage事件中,您可以使用chrome.extension.getViews直接引用window其中一个扩展页面的对象(例如弹出页面,选项页面......).
从其他页面,chrome.extension.getBackgroundPage()给出window对后台页面对象的引用(对于事件页面,使用chrome.runtime.getBackroundPage(callback)).

如果要连接两个帧,请使用Channel messaging API(请参阅whatwg规范Opera的开发文章).使用此方法,即使它们位于不同的原点,您也可以在帧之间建立直接连接!

示例:蹦床

worker.js

var ports = [];
onconnect = function(event) {
    var port = event.ports[0];
    ports.push(port);
    port.start();
    port.onmessage = function(event) {
        for (var i = 0; i < ports.length; ++i) {
            if (ports[i] != port) {
                ports[i].postMessage(event.data);
            }
        }
    };
};
Run Code Online (Sandbox Code Playgroud)

trampoline.js

var worker = new SharedWorker(chrome.runtime.getURL('worker.js'));
worker.port.start();
// Demo: Print the message to the console, and remember the last result
worker.port.onmessage = function(event) {
    console.log('Received message', event.data);
    window.lastMessage = event.data;
};
// Demo: send a message
worker.port.postMessage('Hello');
Run Code Online (Sandbox Code Playgroud)

trampoline.html

<script src="trampoline.js"></script>
Run Code Online (Sandbox Code Playgroud)

contentscript.js

var f = document.createElement('iframe');
f.src = chrome.runtime.getURL('trampoline.html');
f.hidden = true;
(document.body || document.documentElement).appendChild(f);
Run Code Online (Sandbox Code Playgroud)

manifest.json

注意:我把trampoline.js这个答案作为后台脚本来节省空间.从Web工作者的角度来看,发起消息的人并不重要,所以我重新使用了代码来发送和接收消息(毕竟这是一个简单的演示!).

{
    "name": "Trampoline demo",
    "version": "1",
    "manifest_version": 2,
    "background": {
        "scripts": ["trampoline.js"],
        "persistent": true
    },  
    "content_scripts": [{
        "js": ["contentscript.js"],
        "matches": ["<all_urls>"]
    }],
    "web_accessible_resources": [
        "trampoline.html"
    ]   
}
Run Code Online (Sandbox Code Playgroud)

  • @ExpertSystem当在`document_start`上运行内容脚本时,`document.head/body`通常是`null`.`document.head/body`在某些文档中总是为`null`(例如SVG).但是所有文档都有一个根,所以我添加`document.documentElement`作为后备. (2认同)
  • 谢谢,罗布.(我相信我们应该正式宣布Rob"Jon Skeet of Chrome Extensions":P) (2认同)