2012-08-10 67 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; 
    } 
}