【问题标题】:How to create a SharedWorker using a blob?如何使用 blob 创建 SharedWorker?
【发布时间】:2018-11-18 11:27:13
【问题描述】:

我想创建一个 SharedWorker,正如一本好书的一章所述:https://github.com/getify/You-Dont-Know-JS/blob/master/async%20%26%20performance/ch5.md

我能够为普通网络工作者编造一个很好的例子:

function createAsker(limit) {
    var blob = new Blob(["onmessage = function(e) { " +
                           "if (self.higher === undefined) self.higher = " + limit + "; " +
                           "if (self.lower === undefined) self.lower = 1;" +
                           "if (e.data === 'correct') { " +
                             "postMessage('Party time'); " +
                           "} else {" +
                             "if (e.data === 'greater') self.lower = parseInt((self.lower + self.higher) / 2);" +
                             "if (e.data === 'lower') self.higher = parseInt((self.lower + self.higher) / 2);" +
                             "postMessage(parseInt((self.lower + self.higher) / 2));" +
                           "}" +
                         "}"]);
    var blobURL = window.URL.createObjectURL(blob);
    var worker = new Worker(blobURL);
    return worker;
}

var asker = createAsker(1000);

function createAnswerer(limit) {
    var blob = new Blob(["onmessage = function(e) { " +
                            "postMessage((e.data == " + limit + ") ? 'correct' : ((e.data < " + limit + ") ? 'greater' : 'lower'));" +
                         "}"]);
    var blobURL = window.URL.createObjectURL(blob);
    var worker = new Worker(blobURL);
    return worker;
}

var answerer = createAnswerer(42);

asker.onmessage = function(e) {
  console.log('Asker says: ' + e.data);
  if (e.data !== "Party time") {
    setTimeout(function() {answerer.postMessage(e.data)}, 1000);
  }
};

answerer.onmessage = function(e) {
  console.log('Answerer says: ' + e.data);
  setTimeout(function() {asker.postMessage(e.data)}, 1000);
};

asker.postMessage('start');

然而,我在创建共享工作者时遇到了困难。我尝试使用以下代码创建一个:

function createWorker() {
    var blob = new Blob(['addEventListener( "connect", function(evt){ ' +
                            'var port = evt.ports[0]; ' +
                            'port.addEventListener( "message", function(evt){' +
                              'port.postMessage( .. );debugger;' +
                            '} );' +
                            'port.start();' +
                          '} );']);
    var blobURL = window.URL.createObjectURL(blob);
    var w = new SharedWorker(blobURL);
    return w;
}

var w = createWorker();

w.port.start();

w.port.onmessage = function(e) {
  console.log(e.data);
};

w.port.onmessage('foobar');

在发送 foobar 的消息后,我希望我的共享工作者发布一条消息,或者至少我希望由调试器引导到代码中,但是,当我运行此代码时,控制台会给出两个 undefined 作为回应。

【问题讨论】:

  • 我认为你不能从Blob 中创建SharedWorker,因为每个Blob 都有不同的Object URL,并且几乎无法共享。
  • @Bergi 有趣的一点。然而,共享工作者是在 Chrome 中创建的。我并不是说一切都是正确的,如果一切都按预期进行,我不会有任何疑问。但是,如果我们抛开创建 sharedworker 的方式,您是否在传递给 Blob 构造函数的脚本或函数之后的用法中看到此代码中的任何其他问题?
  • w.port.onmessage('foobar'); 看起来肯定是错误的。您不想直接调用事件处理程序。 (如果您使用了w.port.addEventListener("message", function(e) { console.log(e.data); });,它会导致明显的错误消息)。您可能想改用postMessage

标签: javascript web-worker


【解决方案1】:

Base64 编码提供一个永久 URL,直到源代码发生更改。

const source = 'importScript("https://anotherhost/worker.js")';
const url = 'data:application/javascript;base64,' + btoa(source);
const worker = new SharedWorker(url);

它至少在 Chrome 73 和 Firefox 66 中有效。

编码后的 URL 有一个limit to the length,大约 65 KB。

【讨论】:

  • 你可以绕过这个长度限制,首先创建一个更小或最小的SharedWorker,然后让它通过@987654325从它连接到的第一个窗口请求其余代码@。一旦收到它就必须eval() this 进入它自己的全局范围。 (And note that there's a little trick to getting eval() to work in global scope...)。
  • 对已接受答案的小修复。它应该是 importScripts 而不是 importScriptconst source = 'importScripts("https://anotherhost/worker.js")';
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-06
  • 1970-01-01
  • 2017-03-14
  • 2013-06-23
  • 2019-07-23
  • 2021-11-29
相关资源
最近更新 更多