2012-08-10 11 views
14

Chciałbym przekazać funkcję (lub funkcje) za pośrednictwem postMessage() do pracownika sieci, ponieważ nie mogę odwoływać się do zwykłych plików.Jak przekazywać funkcje do JavaScript Web Worker

Aby odłączyć pracownika WWW, przekazuję URL obiektu (utworzony z obiektu Blob) do konstruktora modułu Worker. Potem przekazuję wiadomość, ale jak na razie nie ma szczęścia, umieszczając jakąś funkcję w wiadomości. Komunikat (JSON) nie może zawierać funkcji bezpośrednio (jak określono here) i chociaż importowanie jest teoretycznie dozwolone, nie korzystałem dotąd z niego w Chrome czy Firefox.

Ciało pliku 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> 

Obecnie powoduje ustawienie wartości divText do "sukcesu importScripts".

Czy robię coś nie tak? Czy istnieje inny sposób przekazywania funkcji pracownikom internetowym? Czy to nie jest możliwe?

+4

Hi można podać swoje funkcje "myLib" Używasz here..Thanks – Buzz

Odpowiedz

4

Okazuje się, że ta metoda działa bez zarzutu, nie było po prostu błąd w moim pracownikiem:

var result = greeter("john"); 

powinny być

var result = greet("john"); 

co ma sens - Jestem przechodzącą zmienną logowania do pracownika , ale nie ma powodu, aby znać nazwę zmiennej obiektu, który mijam.

2

Dla tych, którzy szukają bardziej ogólnej odpowiedzi: tutaj jest wtyczka, która pozwala wykonać dowolną funkcję kodu javascript w wątku.

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

traktować je jako "funkcja outsourcingu". Przekazujesz dowolną funkcję do wtyczki jako argument i uzyskujesz wynik zwrotny. Możesz także "outsourcować" metody obiektu, funkcjonować z zależnościami, anonimową funkcją i lambda.

Ciesz się.

--Vadim

+0

Jaka jest licencja na vkthread? Wygląda jak wygodna mała biblioteka. Chciałbym go użyć, ale nie mogę budować rzeczy zależnych od niego bez znajomości licencji. –

+0

Licencja to MIT, co oznacza bezpłatny dla wszystkich bez ograniczeń. – vadimk

0

Tak, oczywiście, że jest to możliwe, I wdrożone go

To jest obietnica, że ​​będzie wykonywał pracownik rodzajowy

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

    }) 
} 

Ogólny plik pracownik 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) 

Używanie go :)

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; 
    } 
} 
Powiązane problemy