Web Worker为什么不能直接调用一个函数?
我们可以使用像这样的HTML5网页工人:Web Worker为什么不能直接调用一个函数?
var worker = new Worker('worker.js');
,但为什么我们不能称这样的功能?
var worker = new Worker(function(){
//do something
});
这是网络工作者设计的方式。他们必须拥有自己的外部JS文件以及由该文件初始化的自己的环境。由于多线程冲突的原因,他们无法与常规全局JS空间共享环境。
网络工作者不允许直接访问你的全局变量的一个原因是,它需要两个环境之间的线程同步,这是不是可用的东西(它会使事情变得非常复杂)。当Web工作者拥有自己独立的全局变量时,除了通过与主JS线程正确同步的消息传递队列之外,他们不能混淆主JS线程。也许有一天,更高级的JS程序员将能够使用传统的线程同步技术来共享对公共变量的访问,但是现在,两个线程之间的所有通信都必须经过消息队列,并且web worker不能访问主要的Javascript线程的环境。
同意,我们有一段时间了,但已经走了。 – 2012-07-06 02:23:03
我认为javascript是单线程的。但是大容器可以打开并运行多线程页面。所以我猜web worker会创建一个新页面(或者称之为新环境)并在其中运行脚本?所以网络工作者可以调用一个外部的JS文件。 – Dozer 2012-07-06 02:42:01
@Dozer - 基本上是正确的。主要的JavaScript线程是单线程的,网络上的很多JavaScript代码都假设这一点。与其添加高级线程同步工具以允许通用多线程,那些设计Web工作者的人决定采取更小的步骤并允许新的线程,但只有当它通过新的JS文件初始化它自己的全局环境并且不能与任何全局访问共享主线程除非通过消息队列同步。这可以防止线程间的全局变量同步问题。 – jfriend00 2012-07-06 02:51:43
按设计网页工作人员是多线程的,javascript是单线程的“ *”多个脚本不能同时运行。
看到imline工人的宗派!这是你会得到最接近的。 – starbeamrainbowlabs 2012-07-06 07:00:09
这个问题已经被问before,但由于某些原因,OP决定将其删除。
我转发我的答案,以防万一需要从函数创建Web工作者的方法。
在this post中,显示了三种方式来从任意字符串创建Web Worker。在这个答案中,我使用了第三种方法,因为它在所有环境中都受支持。
需要一个帮手文件:
// Worker-helper.js
self.onmessage = function(e) {
self.onmessage = null; // Clean-up
eval(e.data);
};
在您的实际工作者,这个辅助文件的使用方法如下:
// Create a Web Worker from a function, which fully runs in the scope of a new
// Worker
function spawnWorker(func) {
// Stringify the code. Example: (function(){/*logic*/}).call(self);
var code = '(' + func + ').call(self);';
var worker = new Worker('Worker-helper.js');
// Initialise worker
worker.postMessage(code);
return worker;
}
var worker = spawnWorker(function() {
// This function runs in the context of a separate Worker
self.onmessage = function(e) {
// Example: Throw any messages back
self.postMessage(e.data);
};
// etc..
});
worker.onmessage = function() {
// logic ...
};
worker.postMessage('Example');
注意,范围是严格分开的。变量只能使用worker.postMessage
和worker.onmessage
来传递。所有消息都是structured clones。
这里假定'Function.toString()'作为一个un-eval反编译器,在某些环境中情况并非如此。谨慎使用! – Qix 2014-11-03 22:52:22
@Qix如果您可以命名至少一个支持Web Workers的通用浏览器,但您的评论会更有帮助,但默认情况下,用户定义的函数上的'toString()'不会返回功能相同的源代码。 – 2014-11-03 23:18:36
浏览器不是唯一的Javascript环境。事实是,这违反了W3C标准以及Ecmascript标准(功能不应该被反编译;支持它的环境只能作为用于调试目的的附加功能)。 – Qix 2014-11-04 02:47:29
这个答案可能有点晚,但我写了一个库来简化网络工作者的使用,它可能适合OP的需要。检查出来:https://github.com/derekchiang/simple-worker
它允许你做这样的事情:
SimpleWorker.run({
func: intensiveFunction,
args: [123456],
success: function(res) {
// do whatever you want
},
error: function(err) {
// do whatever you want
}
})
这看起来很像@ vadimk的vkThread上面的帖子 - 显然不同的项目,但我可以说vkThread工作得很好,并有几种不同的使用方法。 – Nick 2013-10-17 10:43:56
只要用我的小插件https://github.com/zevero/worker-create
,做
var worker_url = Worker.create(function(e){
self.postMessage('Example post from Worker'); //your code here
});
var worker = new Worker(worker_url);
虽然它不是最佳的,它已经在评论中提到,如果您的浏览器支持Web Workers的blobURL,则不需要外部文件。的HTML5Rocks是inspiration我的代码:
function sample(e)
{
postMessage(sample_dependency());
}
function sample_dependency()
{
return "BlobURLs rock!";
}
var blob = new Blob(["onmessage = " + sample + "\n" + sample_dependency]);
var blobURL = window.URL.createObjectURL(blob);
var worker = new Worker(blobURL);
worker.onmessage = function(e)
{
console.log(e.data);
};
worker.postMessage("");
注意事项:
团块工人将无法成功使用相对URL。 HTML5Rocks链接涵盖了这一点,但它不是原始问题的一部分。
人们已经报告了在网络工作人员中使用Blob URL的问题。我试过IE11(无论FCU附带),MS Edge 41.16299(Fall Creator的更新版本),Firefox 57和Chrome 62。没有提供有关Safari支持的线索。我测试过的那些人已经工作了。
注意的是,在斑点构造函数调用“样品”和“sample_dependency”引用隐式调用
Function.prototype.toString()
为sample.toString()
和sample_dependency.toString()
,这比调用toString(sample)
和toString(sample_dependency)
很大的不同。
这是因为它是在搜索如何使用Web Workers而不请求附加文件时出现的第一个stackoverflow。
看了Zevero的回答,他的回购代码看起来很相似。如果你喜欢干净的包装,这大约是他的代码所做的。
最后 - 我是一个noob在这里所以任何/所有的更正赞赏。
另一个可以帮助你的插件是[vkThread](http://www.eslinstructor.net/vkthread/)。看看[http://www.eslinstructor.net/vkthread/](http://www.eslinstructor.net/vkthread/)你会在那里找到例子和文档。 – vadimk 2013-09-16 06:53:46
您需要使用URL,但某些浏览器将允许您使用BLOB URL。有关示例,请参见[this](http://stackoverflow.com/a/6454685/19676)回答。 – Maurice 2012-07-06 06:56:02
正如@Qix在另一个人所说的回应评论中所说,vkThread也是基于function.toString,这会导致浏览器之间的不一致。 – 2015-06-18 09:30:19