Warum kann Web Worker eine Funktion nicht direkt aufrufen?

Lesezeit: 9 Minuten

Benutzer-Avatar
Bulldozer

Wir können den Web Worker in HTML5 wie folgt verwenden:

var worker = new Worker('worker.js');

aber warum können wir eine Funktion wie diese nicht aufrufen?

var worker = new Worker(function(){
    //do something
});

  • Sie müssen eine URL verwenden, aber einige Browser erlauben die Verwendung einer BLOB-URL. Siehe diese Antwort für ein Beispiel.

    – Moritz

    6. Juli 2012 um 6:56 Uhr

  • Ein weiteres Plugin, das Ihnen helfen kann, ist vkThread. Schauen Sie sich an http://www.eslinstructor.net/vkthread/ Dort finden Sie Beispiele und Dokumentationen.

    – Wadimk

    16. September 2013 um 6:53 Uhr


  • Wie @Qix in einem anderen Antwortkommentar sagte, basiert vkThread auch auf function.toString, was zu Inkonsistenzen zwischen Browsern führt.

    – Gestrandetes Kind

    18. Juni 2015 um 9:30 Uhr

Benutzer-Avatar
jfriend00

So sind Webworker konzipiert. Sie müssen über eine eigene externe JS-Datei und eine eigene Umgebung verfügen, die von dieser Datei initialisiert wird. Sie können aus Multithreading-Konfliktgründen keine Umgebung mit Ihrem regulären globalen JS-Bereich teilen.

Ein Grund, warum Webworkern kein direkter Zugriff auf Ihre globalen Variablen gestattet ist, besteht darin, dass dies eine Thread-Synchronisierung zwischen den beiden Umgebungen erfordern würde, die nicht verfügbar ist (und die Dinge ernsthaft verkomplizieren würde). Wenn Webworker ihre eigenen separaten globalen Variablen haben, können sie sich nicht mit dem Haupt-JS-Thread anlegen, außer über die Messaging-Warteschlange, die ordnungsgemäß mit dem Haupt-JS-Thread synchronisiert ist.

Vielleicht werden fortgeschrittenere JS-Programmierer eines Tages in der Lage sein, traditionelle Thread-Synchronisationstechniken zu verwenden, um den Zugriff auf gemeinsame Variablen zu teilen, aber im Moment muss die gesamte Kommunikation zwischen den beiden Threads durch die Nachrichtenwarteschlange gehen und der Webworker hat keinen Zugriff auf die Haupt-JavaScript-Threads Umgebung.

  • Einig, wir sind einige Zeit entfernt, aber wir haben einen Weg zurückgelegt.

    – ShawnDaGeek

    6. Juli 2012 um 2:23 Uhr

  • Ich denke, das Javascript ist Single-Threaded. Aber der Browser kann Seiten mit Multi-Threaded öffnen und ausführen. Also schätze ich, dass der Webworker eine neue Seite erstellt (oder es eine neue Umgebung nennt) und das Skript darin ausführt? Der Webworker kann also einfach eine externe JS-Datei aufrufen.

    – Bulldozer

    6. Juli 2012 um 2:42 Uhr

  • @Dozer – das ist im Grunde richtig. Der Haupt-Javascript-Thread ist Single-Threaded und viele Javascript-Codes im Web gehen davon aus. Anstatt fortschrittliche Tools zur Thread-Synchronisierung hinzuzufügen, um generisches Multithreading zu ermöglichen, entschieden sich die Entwickler von Web Workern für einen kleineren Schritt und erlaubten einen neuen Thread, aber NUR, wenn er seine eigene globale Umgebung über eine neue JS-Datei initialisiert und keinen globalen Zugriff mit teilen kann Haupt-Thread, außer bei Synchronisierung über die Nachrichtenwarteschlange. Dadurch werden Probleme mit der Synchronisierung globaler Variablen zwischen Threads verhindert.

    – jfriend00

    6. Juli 2012 um 2:51 Uhr

  • Ich habe meine Vermutung getestet und sie war falsch. Run js in in page made by window.open() blockiert ebenfalls den Thread.

    – Bulldozer

    6. Juli 2012 um 8:15 Uhr

Benutzer-Avatar
Rob W

Diese Frage wurde schon einmal gestellt, aber aus irgendeinem Grund hat das OP beschlossen, sie zu löschen.

Ich reposte meine Antwort, falls man eine Methode benötigt, um einen Web-Worker aus einer Funktion zu erstellen.


In diesem Beitrag wurden drei Möglichkeiten aufgezeigt, einen Webworker aus einem beliebigen String zu erstellen. In dieser Antwort verwende ich die dritte Methode, da sie in allen Umgebungen unterstützt wird.

Eine Hilfsdatei wird benötigt:

// Worker-helper.js
self.onmessage = function(e) {
    self.onmessage = null; // Clean-up
    eval(e.data);
};

In Ihrem aktuellen Worker wird diese Hilfsdatei wie folgt verwendet:

// Create a Web Worker from a function, which fully runs in the scope of a new
//    Worker
function spawnWorker(func) {
    // Stringify the code. Example:  (function(){/*logic*/}).call(self);
    var code="(" + func + ').call(self);';
    var worker = new Worker('Worker-helper.js');
    // Initialise worker
    worker.postMessage(code);
    return worker;
}

var worker = spawnWorker(function() {
    // This function runs in the context of a separate Worker
    self.onmessage = function(e) {
        // Example: Throw any messages back
        self.postMessage(e.data);
    };
    // etc..
});
worker.onmessage = function() {
    // logic ...
};
worker.postMessage('Example');

Beachten Sie, dass die Bereiche strikt getrennt sind. Variablen können nur mit übergeben und weitergegeben werden worker.postMessage und worker.onmessage. Alle Nachrichten sind strukturierte Klone.

  • Dies setzt voraus Function.toString() arbeitet als unevaluierter Decompiler, was in bestimmten Umgebungen NICHT der Fall ist. Mit Vorsicht verwenden!

    – Qix – MONICA WURDE MISSHANDELT

    3. November 2014 um 22:52 Uhr

  • @Qix Ihr Kommentar wäre hilfreicher, wenn Sie mindestens einen gängigen Browser nennen können, in dem Web Worker unterstützt werden, aber toString() auf einer benutzerdefinierten Funktion gibt standardmäßig keine funktional äquivalente Quelle zurück.

    – Rob W

    3. November 2014 um 23:18 Uhr


  • Browser sind nicht die einzigen Javascript-Umgebungen. Tatsache ist, dass dies sowohl gegen den W3C-Standard als auch gegen die Ecmascript-Standards verstößt (Funktionen sollten nicht dekompiliert werden; Umgebungen, die dies unterstützen, stellen dies nur als zusätzliches Feature für Debugging-Zwecke zur Verfügung).

    – Qix – MONICA WURDE MISSHANDELT

    4. November 2014 um 2:47 Uhr

  • Die Serialisierung von @Qix-Funktionen verstößt gegen keinen Standard (und sicherlich nicht ein w3-Standard, da W3 nicht für die Veröffentlichung von JS-Standards verantwortlich ist …). Insbesondere die aktuelle ECMAScript-Spezifikation besagt, dass die Darstellung implementierungsabhängig ist. Und in der Praxis geben alle modernen JavaScript-Engines ein funktional gleichwertiges Stück JavaScript-Code für benutzerdefinierte Funktionen zurück. Wenn Sie Ihren Standpunkt beweisen wollen, nennen Sie eine nicht-esoterische JavaScript-Umgebung, die Web Worker unterstützt, aber keine Serialisierung von Funktionen.

    – Rob W

    4. November 2014 um 13:31 Uhr

  • Ich habe angegeben, dass die Verwendung von Funktionen in der Art und Weise, wie Sie Webworkern vorschlagen, ein Hack ist und nicht im Standard behandelt wird und daher anfällig für subtile Fehler oder undefiniertes Verhalten ist. Außerdem können Sie nicht davon ausgehen, dass jede Umgebung etwas unterstützt, das nicht im Standard enthalten ist. Ich habe lediglich darauf hingewiesen.

    – Qix – MONICA WURDE MISSHANDELT

    4. November 2014 um 14:09 Uhr

Diese Antwort ist vielleicht etwas spät, aber ich habe eine Bibliothek geschrieben, um die Verwendung von Webworkern zu vereinfachen, und sie könnte den Anforderungen von OP entsprechen. Hör zu: https://github.com/derekchiang/simple-worker

Es erlaubt Ihnen, Folgendes zu tun:

SimpleWorker.run({
  func: intensiveFunction,
  args: [123456],
  success: function(res) {
    // do whatever you want
  },
  error: function(err) {
    // do whatever you want
  }
})

  • Dies sieht dem vkThread-Beitrag von @vadimk oben ziemlich ähnlich – offensichtlich verschiedene Projekte, aber ich kann sagen, dass vkThread gut funktioniert und mehrere verschiedene Methoden zur Verwendung hat.

    – Nik

    17. Oktober 2013 um 10:43 Uhr

WebWorkers-Grundlagen

WebWorker werden ausgeführt in ein eigenständiger Fadenso haben kein Zugang zum Hauptthread, wo Sie sie deklarieren (und umgekehrt). Der resultierende Umfang ist isoliert und eingeschränkt. Aus diesem Grund können Sie beispielsweise das DOM nicht aus dem Worker heraus erreichen.


Kommunikation mit WebWorkern

Da die Kommunikation zwischen Threads notwendig ist, gibt es Mechanismen, um dies zu erreichen. Der Standardkommunikationsmechanismus erfolgt über Nachrichten unter Verwendung von worker.postMessage() Funktion und die worker.onMessage()Event-Handler.

Fortgeschrittenere Techniken sind verfügbar, die SharedArrayBuffers beinhalten, aber es ist nicht mein Ziel, sie zu behandeln. Wenn Sie daran interessiert sind, lesen Sie hier.


Threaded-Funktionen

Das bringt uns der Standard. ES6 stellt uns jedoch genügend Tools zur Verfügung, um ein On-Demand-Callable zu implementieren Threaded-Funktion.

Da man einen Worker aus a bauen kann Klecksund Ihre Funktion kann darin konvertiert werden (mit URL.createObjectURL), müssen Sie nur eine Art implementieren Kommunikationsschicht in beiden Threads, um die Nachrichten für Sie zu bearbeiten und eine natürliche Interaktion zu erhalten.

Versprechen Natürlich sind Sie Ihr Freund, wenn man bedenkt, dass alles passieren wird asynchron.

Wenn Sie diese Theorie anwenden, können Sie das von Ihnen beschriebene Szenario leicht implementieren.


Mein persönlicher Ansatz: ParallelFunction

Ich habe kürzlich eine kleine Bibliothek implementiert und veröffentlicht, die genau das tut, was Sie beschreiben. in weniger als 2 KB (verkleinert).

Es heißt ParallelFunktionund es ist verfügbar in github, npm und ein paar CDNs.

Wie Sie sehen können, entspricht es vollständig Ihrer Anfrage:

// Your function...
let calculatePi = new ParallelFunction( function(n){
    // n determines the precision , and in consequence 
    // the computing time to complete      
    var v = 0;
    for(let i=1; i<=n; i+=4) v += ( 1/i ) - ( 1/(i+2) );
    return 4*v;
});

// Your async call...
calculatePi(1000000).then( r=> console.log(r) );

// if you are inside an async function you can use await...
( async function(){    
    let result = await calculatePi(1000000);
    console.log( result );
})()

// once you are done with it...
calculatePi.destroy();

Nach der Initialisierung können Sie Ihre Funktion beliebig oft aufrufen. a Versprechen zurückgegeben, die aufgelöst wird, wenn Ihre Funktion die Ausführung beendet.

Übrigens gibt es viele andere Bibliotheken.

Verwenden Sie einfach mein kleines Plugin https://github.com/zevero/worker-create

und TU

var worker_url = Worker.create(function(e){
  self.postMessage('Example post from Worker'); //your code here
});
var worker = new Worker(worker_url);

Benutzer-Avatar
lmcdo

Obwohl es nicht optimal ist und in den Kommentaren erwähnt wurde, ist eine externe Datei nicht erforderlich, wenn Ihr Browser blobURLs für Web Worker unterstützt. HTML5Rocks war das Inspiration für meinen Code:

function sample(e)
{
    postMessage(sample_dependency());
}

function sample_dependency()
{
    return "BlobURLs rock!";
}

var blob = new Blob(["onmessage = " + sample + "\n" + sample_dependency]);
var blobURL = window.URL.createObjectURL(blob);
var worker = new Worker(blobURL);

worker.onmessage = function(e)
{
    console.log(e.data);
};

worker.postMessage("");

Vorbehalte:

  • Die Blob-Worker verwenden relative URLs nicht erfolgreich. Der HTML5Rocks-Link deckt dies ab, war jedoch nicht Teil der ursprünglichen Frage.

  • Es wurden Probleme bei der Verwendung von Blob-URLs mit Web Workern gemeldet. Ich habe es mit IE11 (was auch immer mit FCU geliefert wurde), MS Edge 41.16299 (Fall Creator’s Update), Firefox 57 und Chrome 62 versucht. Keine Ahnung von Safari-Unterstützung. Die, die ich getestet habe, haben funktioniert.

  • Beachten Sie, dass „sample“- und „sample_dependency“-Verweise im Blob-Konstruktoraufruf implizit aufrufen Function.prototype.toString() wie sample.toString() und sample_dependency.toString()was etwas ganz anderes ist als ein Anruf toString(sample) und toString(sample_dependency).

Gepostet, weil es der erste Stapelüberlauf ist, der bei der Suche nach der Verwendung von Web Workers ohne Anforderung einer zusätzlichen Datei aufgetreten ist.

Ich habe mir Zeveros Antwort angesehen und der Code in seinem Repo scheint ähnlich zu sein. Wenn Sie einen sauberen Wrapper bevorzugen, ist dies ungefähr das, was sein Code tut.

Zu guter Letzt – ich bin hier ein Noob, also sind alle Korrekturen willkommen.

Benutzer-Avatar
ShawnDaGeek

Per Design sind Web Worker Multi-Threaded, Javascript ist Single-Threaded”*”Mehrere Skripte können nicht gleichzeitig ausgeführt werden.

beziehen auf: http://www.html5rocks.com/en/tutorials/workers/basics/

  • Siehe den Abschnitt über Imline-Arbeiter! Es ist das nächste, was Sie bekommen werden.

    – Starbeamrainbowlabs

    6. Juli 2012 um 7:00 Uhr

1196370cookie-checkWarum kann Web Worker eine Funktion nicht direkt aufrufen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy