359 Stimmen

Webworker ohne separate Javascript-Datei?

Soweit ich das beurteilen kann, müssen Web Worker in einer separaten JavaScript-Datei geschrieben und wie folgt aufgerufen werden:

new Worker('longrunning.js')

Ich verwende den Closure-Compiler, um meinen gesamten JavaScript-Quellcode zusammenzufassen und zu verkleinern, und ich möchte meine Worker nicht in separaten Dateien verteilen müssen. Gibt es eine Möglichkeit, dies zu tun?

new Worker(function() {
    //Long-running work here
});

Angesichts der Tatsache, dass erstklassige Funktionen für JavaScript so wichtig sind, stellt sich die Frage, warum die Standardmethode für die Arbeit im Hintergrund eine weitere JavaScript-Datei vom Webserver laden muss.

1voto

59naga Punkte 111

Hier Konsole:

var worker=new Worker(window.URL.createObjectURL(new Blob([function(){
  //Long-running work here
  postMessage('done');
}.toString().split('\n').slice(1,-1).join('\n')],{type:'text/javascript'})));

worker.addEventListener('message',function(event){
  console.log(event.data);
});

1voto

Versuchen Sie, jThread zu verwenden. https://github.com/cheprasov/jThread

// You can use simple calling like this
jThread(
    function(arr){
        //... some code for Worker
        return arr;
    }
    ,function(arr){
        //... done code
    }
)( [1,2,3,4,5,6,7] ); // some params

1voto

Miguel Q. Punkte 537

Ich denke, der bessere Weg, dies zu tun ist mit einem Blob-Objekt, unten können Sie ein einfaches Beispiel zu sehen.

// create a Blob object with a worker code
var blob = new Blob(["onmessage = function(e) { postMessage('msg from worker'); }"]);

// Obtain a blob URL reference to our worker 'file'.
var blobURL = window.URL.createObjectURL(blob);

// create a Worker
var worker = new Worker(blobURL);
worker.onmessage = function(e) {
  console.log(e.data);
};
worker.postMessage("Send some Data");

0voto

Z.JC Punkte 1

Ich verwende Code wie dieser, können Sie Ihre onmessage als eine Funktion anders als reiner Text definieren, so dass der Editor Ihren Code markieren kann und jshint funktioniert.

const worker = createWorker();

createWorker() {
    const scriptContent = getWorkerScript();
    const blob = new Blob([
        scriptContent,
    ], {
        type: "text/javascipt"
    });
    const worker = new Worker(window.URL.createObjectURL(blob));
    return worker;
}

getWorkerScript() {
    const script = {
        onmessage: function (e) {
            console.log(e);
            let result = "Hello " + e.data
            postMessage(result);
        }
    };
    let content = "";
    for (let prop in script){
        content += `${prop}=${script[prop].toString()}`;
    }
    return content;
}

0voto

Fernando Carvajal Punkte 1735

Ja, es ist möglich, ich habe es mit Blob-Dateien und Übergabe eines Rückrufs

Ich werde Ihnen zeigen, was eine von mir geschriebene Klasse tut und wie sie die Ausführung von Rückrufen im Hintergrund verwaltet.

Zuerst instanziieren Sie die GenericWebWorker mit den Daten, die Sie an den Callback übergeben möchten, der in der Web Worker die Funktionen enthält, die Sie verwenden möchten, in diesem Fall eine Zahl, ein Datum und eine Funktion namens blocker

var worker = new GenericWebWorker(100, new Date(), blocker)

Diese Blockerfunktion führt ein unendliches while für n Milisekunden aus

function blocker (ms) {
    var now = new Date().getTime();
    while(true) {
        if (new Date().getTime() > now +ms)
            return;
    }   
}

und dann verwenden Sie es wie folgt

worker.exec((num, date, fnBlocker) => {
    /*Everithing here does not block the main thread
      and this callback has access to the number, date and the blocker */
    fnBlocker(10000) //All of this run in backgrownd
    return num*10

}).then(d => console.log(d)) //Print 1000

Jetzt wird es Zeit, die Magie im folgenden Beispiel zu sehen

/*https://github.com/fercarvo/GenericWebWorker*/
class GenericWebWorker {
    constructor(...ags) {
        this.args = ags.map(a => (typeof a == 'function') ? {type:'fn', fn:a.toString()} : a)
    }

    async exec(cb) {
        var wk_string = this.worker.toString();
        wk_string = wk_string.substring(wk_string.indexOf('{') + 1, wk_string.lastIndexOf('}'));            
        var wk_link = window.URL.createObjectURL( new Blob([ wk_string ]) );
        var wk = new Worker(wk_link);

        wk.postMessage({ callback: cb.toString(), args: this.args });

        var resultado = await new Promise((next, error) => {
            wk.onmessage = e => (e.data && e.data.error) ? error(e.data.error) : next(e.data);
            wk.onerror = e => error(e.message);
        })

        wk.terminate(); window.URL.revokeObjectURL(wk_link);
        return resultado
    }

    async parallel(arr, cb) {
        var res = [...arr].map(it => new GenericWebWorker(it, ...this.args).exec(cb))
        var all = await Promise.all(res)
        return all
    }

    worker() {
        onmessage = async function (e) {
            try {                
                var cb = new Function(`return ${e.data.callback}`)();
                var args = e.data.args.map(p => (p.type == 'fn') ? new Function(`return ${p.fn}`)() : p);

                try {
                    var result = await cb.apply(this, args); //If it is a promise or async function
                    return postMessage(result)

                } catch (e) { throw new Error(`CallbackError: ${e}`) }
            } catch (e) { postMessage({error: e.message}) }
        }
    }
}

function blocker (ms) {
    var now = new Date().getTime();
    while(true) {
        if (new Date().getTime() > now +ms)
            return;
    }   
}

setInterval(()=> console.log("Not blocked " + Math.random()), 1000)

console.log("\n\nstarting blocking code in Worker\n\n")

var worker = new GenericWebWorker(100, new Date(), blocker)

worker.exec((num, date, fnBlocker) => {
    fnBlocker(7000) //All of this run in backgrownd
    return num*10    
})
.then(d => console.log(`\n\nEnd of blocking code: result ${d}\n\n`)) //Print 1000

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X