2012-08-10 7 views
14

Ich möchte eine Funktion (oder Funktionen) über eine postMessage() an einen Web-Worker übergeben, weil ich nicht auf normale Dateien verweisen kann.So übergeben Sie Funktionen an JavaScript Web Worker

Um den Web-Worker auszuschalten, übergebe ich eine Objekt-URL (erstellt aus einem Blob) an den Worker-Konstruktor. Dann gebe ich eine Nachricht weiter, aber bisher kein Glück, eine Funktion in die Nachricht zu setzen. Die (JSON) -Nachricht darf keine Funktionen direkt enthalten (wie vorgeschrieben here), und obwohl importScripts theoretisch erlaubt ist, hatte ich bisher keinen Erfolg bei der Verwendung in Chrome oder Firefox.

Der Körper der HTML-Datei:

<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> 

Derzeit führt er den divText Wert auf "importScripts Erfolg".

Mache ich etwas falsch? Gibt es eine andere Möglichkeit, Funktionen an Web-Arbeiter weiterzugeben? Oder ist das nicht möglich?

+4

Hallo Sie Ihre "mylib" Funktionen zur Verfügung stellen können Sie here..Thanks verwenden – Buzz

Antwort

4

Stellt sich diese Methode gut funktioniert, gibt nur einen Fehler in meinem Arbeiter war:

var result = greeter("john"); 

var result = greet("john"); 

was Sinn macht, sollte - ich bin die Greeter-Variable auf den Arbeiter vorbei , aber es gibt keinen Grund dafür, den Variablennamen des Objekts zu kennen, das ich überlasse.

2

Für diejenigen, die generische Antwort suchen: Hier ist ein Plugin, mit dem Sie jede Funktion Ihres Javascript-Codes in einem Thread ausführen können.

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

Betrachten Sie es als "Funktion Outsourcing". Sie übergeben eine Funktion als Argument an das Plugin und erhalten das Ergebnis im Callback. Sie können auch die Methoden des Objekts "outsourcen", funktionieren mit Abhängigkeiten, anonymer Funktion und Lambda.

Genießen.

--Vadim

+0

Was die Lizenz auf vkthread ist? Sieht aus wie eine praktische kleine Bibliothek. Würde mich freuen, es zu benutzen, aber ich kann Sachen davon nicht abhängig bauen, ohne die Lizenz zu kennen. –

+0

Die Lizenz ist MIT, was für alle kostenlos und ohne Einschränkungen bedeutet. – vadimk

0

Ja, natürlich ist es möglich, implementiert ich es

Dies ist ein Versprechen, dass der generischen Arbeiter

/* 
    @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("}")) 
      } 
     } 

    }) 
} 

Die generische Arbeiter-Datei ausgeführt wird 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) 

Mit ihm :)

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; 
    } 
} 
Verwandte Themen