HTML5 unterstützt APIs wie Web Worker und ermöglicht Webseiten, Multi-Thread-Code in einer sicheren Situation auszuführen. Web Worker unterliegt jedoch tatsächlich vielen Einschränkungen, da sie keine Speicherdaten freigeben und nur Nachrichten verwenden kann, um den Zustand zu informieren, sodass sie nicht einmal im wahrsten Sinne als "Multi-Threading" bezeichnet werden kann.
Die Benutzeroberfläche des Web Worker ist sehr unpraktisch zu verwenden. Es wird im Grunde genommen mit einer Sandkiste geliefert, die eine unabhängige JS -Datei in der Sandbox ausführt und mit dem Hauptfaden über Postmessage und OnMessge kommuniziert:
Die Codekopie lautet wie folgt:
var Worker = neuer Arbeiter ("my.js");
var bündel = {message: 'Hallo Welt', id: 1};
Worker.PostMessage (Bundle); // Postmessage kann in der Vergangenheit ein serialisierbares Objekt übergeben
Worker.onMessage = Funktion (evt) {
console.log (evt.data); // Vergleiche Objekte, die im Arbeiter mit Objekten im Haupt -Thread zurückgegeben wurden
console.log (bündel); // {Nachricht: 'Hallo Welt', ID: 1}
}
Die Codekopie lautet wie folgt:
// in my.js
onMessage = function (evt) {
var data = evt.data;
Data.id ++;
Postmessage (Daten); // {Nachricht: 'Hallo Welt', ID: 2}
}
Das Ergebnis ist festzustellen, dass sich die ID der im Thread erhaltenen Daten erhöht hat, aber nachdem sie zurückgegeben wurde, wird die ID im Bündel des Haupt -Threads nicht geändert. Daher wird das im Thread übergebene Objekt tatsächlich kopiert. Auf diese Weise teilt der Thread die Daten nicht aus, vermeidet Lesen und Schreiben von Konflikten, sodass er sicher ist. Die Kosten für die Gewährleistung der Gewinde sind die Möglichkeit, die Fähigkeit zu begrenzen, Hauptfadenobjekte im Thread zu betreiben.
Ein solcher begrenzter Multi-Threading-Mechanismus ist unpraktisch zu verwenden. Natürlich hoffen wir, dass der Arbeiter die Fähigkeit unterstützen kann, den Code gleichzeitig Multi-Threading zu betreiben. Unterstützen Sie beispielsweise Code, der wie folgt aussieht:
Die Codekopie lautet wie folgt:
var Worker = neuer Threadworker (Bundle /*Shared OBJ* /);
Worker.run (Funktion (Bündel) {
// mach sth im Arbeiter -Thread ...
this.runonuithread (Funktion (Bündel /*Shared OBJ* /) {
// mach im Haupt UI -Thread ...
});
// ...
});
In diesem Code können wir nach dem Start eines Arbeiters jeden Code im Arbeiter ausführen lassen, und wenn wir den UI -Thread (z. B. das Lesen und Schreiben des DOM) bedienen müssen, können wir zum Haupt -Thread zurückkehren, um dies durchzuführen.
Wie kann ich diesen Mechanismus implementieren? Schauen Sie sich den folgenden Code an:
Die Codekopie lautet wie folgt:
Funktion WorkerThread (SharedObj) {
this._worker = new Worker ("thread.js");
this._completes = {};
this._task_id = 0;
this.sharedObj = SharedObj;
var self = this;
this._worker.onmessage = function (evt) {
var ret = evt.data;
if (ret .__ ui_task __) {
// Auf der UI -Aufgabe ausführen
var fn = (neue Funktion ("return"+ret .__ ui_task __)) ();
fn (ret.sharedobj);
}anders{
self.sharedObj = ret.sharedobj;
self._completes [ret.taskId] (ret);
}
}
}
WorkerThread.Prototype.run = Funktion (Aufgabe, vollständig) {
var _task = {__Thread_task __: Task.toString (), SharedObj: this.sharedObj, TaskId: this._task_id};
this._completes [this._task_id ++] = vollständig;
this._worker.postMessage (_task);
}
Der obige Code definiert ein Threadworker -Objekt. Dieses Objekt erstellt einen Webarbeiter, der Thread.js ausführt, das Shared Object SharedObj speichert und die von Thread.js zurückgesendeten Nachrichten verarbeitet.
Wenn eine ui_task -Nachricht in thread.js zurückgeführt wird, führen Sie die von dieser Nachricht übergebene Funktion aus. Andernfalls führen wir den vollständigen Rückruf von Run aus. Lassen Sie uns sehen, wie Thread.js geschrieben wird:
Die Codekopie lautet wie folgt:
onMessage = function (evt) {
var data = evt.data;
if (data && data .__ thread_task __) {
var task = data .__ thread_task__;
versuchen{
var fn = (neue Funktion ("return"+task)) ();
var ctx = {
Threadsignal: wahr,
Schlaf: Funktion (Intervall) {
ctx.threadsignal = false;
setTimeout (_run, Intervall);
},
Runonuithread: Funktion (Aufgabe) {
postMessage ({__ ui_task __: task.toString (), SharedObj: data.sharedObj});
}
}
Funktion _run () {
ctx.threadsignal = true;
var ret = fn.call (ctx, data.sharedObj);
postMessage ({Fehler: NULL, returnValue: ret, __Thread_task __: Aufgabe, SharedObj: Data.SharedObj, TaskId: Data.TaskId});
}
_run (0);
} catch (ex) {
postMessage ({error: ex.toString (), returnValue: null, SharedObj: data.sharedObj});
}
}
}
Es ist zu sehen, dass Thread.js Nachrichten aus UI -Threads empfängt, von denen das wichtigste Thread_task ist. Dies ist die "Aufgabe", die von UI -Threads übergeben wird, die vom Worker -Thread ausgeführt werden müssen. Da die Funktion nicht serialisierbar ist, wird sie eine Zeichenfolge übergeben. Der Worker -Thread analysiert die Zeichenfolge in eine Funktion, um die vom Haupt -Thread übermittelten Aufgaben auszuführen (beachten Sie, dass das SharedObj in der Aufgabe freigegeben wird). Nach Abschluss der Ausführung wird das Rückgabeergebnis über die Nachricht an den UI -Thread übergeben. Schauen wir uns zusätzlich zum Rückgabewert des Renditewerts das gemeinsam genutzte Objekt SharedObj genauer an. Beim Zurückgeben, da der Worker -Thread und der UI -Thread das Objekt nicht teilen, synchronisieren wir die Objekte durch Zuordnung künstlich auf beiden Seiten (ist dieser Thread sicher? Warum?)
Sie können sehen, dass der gesamte Prozess nicht kompliziert ist. Nach dieser Implementierung kann dieser Threadworker die folgenden zwei Verwendungen haben:
Die Codekopie lautet wie folgt:
var t1 = new WorkerThread ({i: 100} /*Shared OBJ* /);
setInterval (function () {
t1.run (function (sharedObj) {
Return SharedObj.i ++;
},
Funktion (r) {
console.log ("t1>" + r.returnValue + ":" + r.Error);
}
);
}, 500);
var t2 = new WorkerThread ({i: 50});
t2.run (Funktion (SharedObj) {
während (this.threadsignal) {
SharedObj.i ++;
this.runonuithread (function (sharedObj) {
W ("Body ul"). AppendChild ("<li>"+SharedObj.i+"</li>");
});
this.sleep (500);
}
Return Sharedobj.i;
}, function (r) {
console.log ("t2>" + r.returnValue + ":" + r.Error);
});
Diese Verwendung gibt dem Code eine gute Struktur, Flexibilität und Wartbarkeit sowohl in Form als auch in semantischen Begriffen.
Okay, das ist alles für die Diskussion über die Verwendung von Web Worker. Interessierte Schüler können sich dieses Projekt ansehen: https://github.com/akira-cn/workerthread.js (da der Arbeiter Server-Tests verwenden muss, habe ich speziell einen Nachahmer-Httpd.js in das Projekt eingelegt, was einen sehr einfachen HTTP-Dienst JS ist, und Sie können es direkt mit Knoten mit Node ausführen).