2012-08-10 63 views
14

我想通过postMessage()将一个函数(或函数)传递给Web Worker,因为我无法引用常规文件。如何将函数传递给JavaScript Web Worker

为了关闭web worker,我将一个对象URL(从Blob创建)传递给Worker构造函数。然后我传递一条消息,但到目前为止没有运气在消息中添加一个函数。 (JSON)消息不能直接包含函数(按照here的规定),尽管理论上允许importScripts,但在Chrome或Firefox中使用它仍然没有成功。

html文件的正文:

<div id="divText">1234</div> 
<script> 
    var greeter = function greet(name) { 
     return "hello " + name; 
    }; 
    function webWorkerWorker() { 
     self.postMessage("started1"); 
     self.onmessage = function(event) { 
      importScripts(event.data.content); 
      self.postMessage("importScripts success"); 
      var result = greeter("john"); 
      self.postMessage(result); 
     }; 
    } 
    var functionBody = mylib.extractFunctionBody(webWorkerWorker); 
    var functionBlob = mylib.createBlob([functionBody]); 
    var functionUrl = mylib.createObjectURL(functionBlob); 

    var functionBody2 = mylib.extractFunctionBody(greeter); 
    var functionBlob2 = mylib.createBlob([greeter]); 
    var functionUrl2 = mylib.createObjectURL(functionBlob2); 

    var worker = new Worker(functionUrl); 
    worker.onmessage = function(event) { 
     document.getElementById("divText").innerHTML = event.data; 
    } 
    worker.postMessage({ 
       type: "init", 
       content: functionUrl2 
      }); 
</script> 

目前,它导致设置divText值 “importScripts成功”。

我做错了什么?有没有另外一种方法可以将这些功能传递给网络工作者?还是不可能?

+4

嗨,你可以提供你的 “MYLIB” 功能,您使用的here..Thanks – Buzz 2013-10-16 07:18:13

回答

4

事实证明这种方法效果很好,也仅仅是在我的工作人员的错误:

var result = greeter("john"); 

应该

var result = greet("john"); 

这是有道理的 - 我经过迎宾变量工人,但没有理由知道我传递的对象的变量名称。

2

对于那些正在寻找更通用的答案: 这是一个插件,它允许您在一个线程中执行您的JavaScript代码的任何功能。

http://www.eslinstructor.net/vkthread/

认为这是 “功能外包”。您将任何函数作为参数传递给插件,并在回调中获得结果。你也可以“外包”对象的方法,函数依赖,匿名函数和lambda。

享受。

--Vadim

+0

什么是对vkthread许可证?看起来像一个方便的小型图书馆。会喜欢使用它,但我不能在不知道许可证的情况下构建依赖于它的东西。 – 2017-03-30 19:32:46

+0

许可证是麻省理工学院,这对所有人都是免费的,没有任何限制。 – vadimk 2017-03-31 00:42:43

0

是的,当然有可能,我实现它

这是将执行普通工人

/* 
    @data.context, The context where the callback functions arguments are, ex: window 
    @data.callback, ["fn_name1", "fn_name2", function (fn1, fn2) {}] 
     The callback will be executed, and you can pass other functions to that cb 
    @worker_url string url of generic web worker 
*/ 
function genericWorker(worker_url, data) { 
    return new Promise(function (resolve, reject) { 

     if (!data.callback || !Array.isArray(data.callback)) 
      return reject("Invalid data") 

     var callback = data.callback.pop() 
     var functions = data.callback 
     var context = data.context 

     if (!worker_url) 
      return reject("Worker_url is undefined") 

     if (!callback) 
      return reject("A callback was expected") 

     if (functions.length>0 && !context) 
      return reject("context is undefined") 

     callback = fn_string(callback) //Callback to be executed 
     functions = functions.map((fn_name)=> { return fn_string(context[fn_name]) }) 

     var worker = new Worker(worker_url) 

     worker.postMessage({ callback: callback, functions: functions }) 

     worker.addEventListener('error', function(error){ 
      return reject(error.message) 
     }) 

     worker.addEventListener('message', function(e) { 
      resolve(e.data) 
      worker.terminate() 

     }, false) 


     //From function to string, with its name, arguments and its body 
     function fn_string (fn) { 
      var name = fn.name 
      fn = fn.toString() 

      return { 
       name: name, 
       args: fn.substring(fn.indexOf("(") + 1, fn.indexOf(")")), 
       body: fn.substring(fn.indexOf("{") + 1, fn.lastIndexOf("}")) 
      } 
     } 

    }) 
} 

的通用的工作文件中的承诺worker_for_anything.js

self.addEventListener('message', function(e) {  
    var worker_functions = {} //Functions used by callback 
    var args = [] //Arguments of the callback 

    for (fn of e.data.functions) { 
     worker_functions[fn.name] = new Function(fn.args, fn.body) 
     args.push(fn.name) 
    } 

    var callback = new Function(e.data.callback.args, e.data.callback.body) //Callback passed and ready to be executed  
    args = args.map((fn_name) => { return worker_functions[fn_name] }) //FUnctions loaded as arguments 
    var result = callback.apply(null, args) //executing callback with function arguments 
    self.postMessage(result) 

}, false) 

使用它:)

var data = { 
    context: window, //the context of the functions passed, ex: window for blockCpu 
    callback: ["blockCpu", function (bla) { 
     bla(7000) //blocking for 7000 ms 
     return "bla" //This return is catched in the promise 
    }] 
} 

genericWorker("/worker_for_anything.js", data) 
    .then(function (result){ 
     console.log("result", result) 

    }).catch((error)=> { console.log(error) }) 

//random blocking function 
function blockCpu(ms) { 
    var now = new Date().getTime(); 
    var result = 0 
    while(true) { 
     result += Math.random() * Math.random(); 
     if (new Date().getTime() > now +ms) 
      return; 
    } 
}