我可以生成一个 Web Worker 并从父“进程”注入 JavaScript(由父进程在运行时创建)到其中吗?

问题描述 投票:0回答:2

是否可以生成一个 Web Worker,并以某种方式从父线程将父生成的 JavaScript 注入其中? IE。不必让工作人员包含文件,而是我希望父级以某种方式注入它。

一个示例可能是父级在运行时创建一堆数学函数,然后创建一个 Web Worker 来运行它们。

javascript web-worker
2个回答
2
投票

一种选择是通过常用渠道发送函数代码并使用构造函数

new Function()
(或
eval()
)重新创建函数。

在这两种情况下,您都应该检查实际传输的内容,以防止安全风险。

主要脚本

// your function given as arguments and code
var funktion = {
  args: ['a', 'b' ],
  source: 'return a + b;'
};

// send it to your worker
worker.postMessage( funktion );

工人

self.addEventListener( 'message', function( msg ){

  // build array for constructor arguments
  var args = [ null ].concat( fk.a, fk.c );

  // create function
  var yourFunc = new (Function.prototype.bind.apply(Function, args));

  // use yourFunc
});

这使用了

Function
构造函数的动态使用,如这个答案中所述。


使用

eval()
可能会更简单,具体取决于您如何拥有函数代码:

主要脚本

// your function given as arguments and code
var funktion = "function add(a,b){ return a + b; }";

// send it to your worker
worker.postMessage( funktion );

工人

self.addEventListener( 'message', function( msg ){      

  // create function
  var yourFunc = eval( "(function(){ return " + funktion + "; })()" );

  // use yourFunc
});

1
投票

这个问题已经有近 10 年历史了,所以自提出以来情况已经发生了变化。还有人在没有上下文的情况下询问“注入函数”的含义。您想将单个函数注入到现有环境中,还是想运行整个脚本,或者您想将函数注入到脚本中。

在任何情况下,您都可以通过 blob 在工作线程中运行脚本

const script = `
function doIt() {
  console.log('hello world');
}
doIt();
`;
const blob = new Blob([script], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const worker = new Worker(url);

如果运行上面的脚本并检查 JavaScript 控制台,您会看到它运行了

另一个解决方案是运行一个服务工作者。 Service Worker 有效地拦截来自页面的网络请求,并让您在将请求发送到网络本身之前对其应用 JavaScript。

因此,您可以有效地从服务工作人员返回您自己的字符串,以响应来自网页或工作人员的请求。您可以将函数放入这些字符串中,然后可以通过将字符串发送给服务工作者来提供字符串

伪代码

// service-worker.js
let injectString = '';

self.addEventListener('fetch', (event) => {

  event.respondWith(async function() {
    const url = new URL(event.request.url);
    if (url.pathname === 'inject-fn.js')
      const response = new Response(injectString, {
        headers: {'Content-Type': 'application/javascript'},
      });
      return response;
    }
    return await fetch(event.request);
  }());
}

self.addEventListener('message', (event) => {
  injectString = event.data;
});

这使得如果工作人员请求

'inject-fn.js'
那么它将收到存储在
injectString
中的字符串,否则它将正常进入网络

要设置字符串,您可以向服务工作人员发送消息并加载脚本

  const worker = navigator.serviceWorker?.controller || navigator.serviceWorker?.active;

  worker.postMessage(`
    function doIt() {
      console.log('hello world');
    }
  `);
  
  new Worker('inject-fn.js');

您可能需要附加查询或其他内容以确保浏览器不会从缓存加载“inject-fn.js”。如

  new Worker(`inject-fn.js?${Math.random()});

使用 service-worker 的优点是从页面的 POV 来看,脚本来自相同的 URL,而它们不是通过 blob 来的,因此无法在没有绝对路径的情况下引用资源。

使用服务人员的缺点是他们很挑剔,至少根据我的经验。

注意:上面的代码是伪代码。正确启动服务工作线程并与其通信需要更多代码。 这个网站使用了这两种技术。可以的时候服务人员。当它不能时的斑点。

© www.soinside.com 2019 - 2024. All rights reserved.