2012-08-10 20 views
14

Vorrei passare una funzione (o funzioni) tramite postMessage() a un web worker, perché non posso fare riferimento a file regolari.Come passare le funzioni a JavaScript Web Worker

Per disattivare il web worker, sto passando un URL oggetto (creato da un BLOB) al costruttore Worker. Quindi sto trasmettendo un messaggio, ma finora non ho avuto fortuna a inserire una funzione nel messaggio. Il messaggio (JSON) non può contenere direttamente le funzioni (come stabilito here) e sebbene importScripts sia teoricamente consentito, non ho avuto alcun successo nell'usarlo finora in Chrome o Firefox.

Il corpo del file 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> 

Attualmente il risultato e l'impostazione del valore divText a "importScripts successo".

Sto facendo qualcosa di sbagliato? C'è un altro modo in cui le funzioni possono essere passate ai web worker? O non è possibile?

+4

Hi è possibile fornire le funzioni "mylib" si utilizza here..Thanks – Buzz

risposta

4

Risulta questo metodo funziona bene, c'era solo un bug nel mio operaio:

var result = greeter("john"); 

dovrebbe essere

var result = greet("john"); 

che ha un senso - sto passando la variabile di benvenuto al lavoratore , ma non c'è ragione per sapere il nome della variabile dell'oggetto che sto passando.

2

Per coloro che cercano una risposta più generica: ecco un plug-in che consente di eseguire qualsiasi funzione del codice javascript in una discussione.

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

considerarlo come "la funzione di outsourcing". Si passa qualsiasi funzione al plugin come argomento e si ottengono risultati in callback. Puoi anche "esternalizzare" i metodi dell'oggetto, funzionare con dipendenze, funzioni anonime e lambda.

Divertiti.

--Vadim

+0

Qual è la licenza su vkthread? Sembra una piccola biblioteca conveniente. Mi piacerebbe usarlo ma non posso costruire cose che dipendono da esso senza conoscere la licenza. –

+0

La licenza è MIT, che significa gratis per tutti senza restrizioni. – vadimk

0

Sì, naturalmente è possibile, ho implementato è

Questa è una promessa che eseguirà l'operaio generico

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

    }) 
} 

Il file operaio generico 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) 

Usandolo :)

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; 
    } 
} 
Problemi correlati