2012-08-10 47 views
14

Me gustaría pasar una función (o funciones) a través de un postMessage() a un trabajador web, porque no puedo hacer referencia a archivos regulares.Cómo pasar funciones a JavaScript Web Worker

Para expulsar al trabajador web, paso una URL de objeto (creada a partir de una Blob) al constructor Trabajador. Luego estoy pasando un mensaje, pero hasta ahora no tuve suerte poniendo una función en el mensaje. El mensaje (JSON) no puede contener funciones directamente (como se estipuló en here), y aunque importScripts está teóricamente permitido, hasta ahora no he tenido éxito en utilizarlo en Chrome o Firefox.

El cuerpo del archivo 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> 

Actualmente se lleva a configurar el valor divText de "éxito importScripts".

¿Estoy haciendo algo mal? ¿Hay alguna otra forma en que las funciones se puedan pasar a los trabajadores de la web? ¿O acaso no es posible?

+4

Hola puede ofrecerle sus funciones "MYLIB" está utilizando here..Thanks – Buzz

Respuesta

4

Resulta que este método funciona bien, no era más que un error en mi trabajador:

var result = greeter("john"); 

debería ser

var result = greet("john"); 

que tiene sentido - Estoy pasando la variable bienvenida al trabajador , pero no hay razón para que sepa el nombre de la variable del objeto que estoy pasando.

2

Para aquellos que buscan una respuesta más genérica: aquí hay un complemento que le permite ejecutar cualquier función de su código javascript en un hilo.

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

lo consideran como "función de la externalización". Pasas cualquier función al complemento como argumento y obtienes resultados en la devolución de llamada. También puede "externalizar" los métodos del objeto, funcionar con dependencias, función anónima y lambda.

Disfrútalo.

--Vadim

+0

¿Cuál es la licencia de vkthread? Parece una pequeña biblioteca conveniente. Me encantaría usarlo, pero no puedo construir cosas que dependan de él sin conocer la licencia. –

+0

La licencia es MIT, lo que significa gratis para todos sin restricciones. – vadimk

0

Sí, por supuesto que es posible, yo implementé

Esta es una promesa que se ejecutará el trabajador genérico

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

    }) 
} 

El archivo trabajador genérico 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) 

Su uso :)

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; 
    } 
} 
Cuestiones relacionadas