是否可以生成一个 Web Worker,并以某种方式从父线程将父生成的 JavaScript 注入其中? IE。不必让工作人员包含文件,而是我希望父级以某种方式注入它。
一个示例可能是父级在运行时创建一堆数学函数,然后创建一个 Web Worker 来运行它们。
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
});
这个问题已经有近 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 来的,因此无法在没有绝对路径的情况下引用资源。
使用服务人员的缺点是他们很挑剔,至少根据我的经验。
注意:上面的代码是伪代码。正确启动服务工作线程并与其通信需要更多代码。 这个网站使用了这两种技术。可以的时候服务人员。当它不能时的斑点。