Heim  >  Artikel  >  Web-Frontend  >  Recherche zur Web-Worker-Multithread-API in JavaScript_Javascript-Kenntnissen

Recherche zur Web-Worker-Multithread-API in JavaScript_Javascript-Kenntnissen

WBOY
WBOYOriginal
2016-05-16 16:28:391606Durchsuche

HTML5 unterstützt APIs wie Web Worker und ermöglicht es Webseiten, Multithread-Code sicher auszuführen. Tatsächlich unterliegt Web Worker jedoch vielen Einschränkungen, da er Speicherdaten nicht wirklich gemeinsam nutzen kann und Statusbenachrichtigungen nur über Nachrichten senden kann, sodass er nicht einmal im eigentlichen Sinne als „Multithreading“ bezeichnet werden kann.

Die Benutzeroberfläche von Web Worker ist im Grunde genommen mit einer Sandbox ausgestattet, führt eine unabhängige JS-Datei in der Sandbox aus und kommuniziert mit dem Hauptthread über postMessage und onMessage:

Code kopieren Der Code lautet wie folgt:

var worker = new Worker("my.js");
var bundle = {message:'Hello world', id:1};
worker.postMessage(bundle); //postMessage kann ein serialisierbares Objekt übergeben
worker.onmessage = function(evt){
Console.log(evt.data); //Vergleiche das vom Worker zurückgegebene Objekt mit dem Objekt im Hauptthread
console.log(bundle); //{message:'Hello world', id:1}
}

Code kopieren Der Code lautet wie folgt:

//in my.js
onmessage = function(evt){
var data = evt.data;
Daten.id ;
PostMessage(data); //{message:'Hello world', id:2}
}

Die erhaltenen Ergebnisse zeigen, dass die ID der im Thread erhaltenen Daten zugenommen hat, die ID im Bündel des Hauptthreads sich jedoch nach der Rückgabe nicht geändert hat. Daher hat sich das im Thread übergebene Objekt nicht geändert wird tatsächlich kopiert. Wenn dies der Fall ist, teilen die Threads keine Daten und vermeiden Lese- und Schreibkonflikte, sodass dies sicher ist. Der Preis für die Gewährleistung der Thread-Sicherheit besteht darin, die Möglichkeit zur Manipulation von Haupt-Thread-Objekten im Thread einzuschränken.

Ein solch eingeschränkter Multithreading-Mechanismus ist sehr umständlich zu verwenden. Wir hoffen auf jeden Fall, dass Worker es unterstützen kann, den Code so aussehen zu lassen, als ob er in der Lage wäre, mehrere Threads gleichzeitig zu betreiben Folgendes:

Code kopieren Der Code lautet wie folgt:

var worker = new ThreadWorker(bundle /*shared obj*/);

worker.run(function(bundle){
//etwas im Worker-Thread machen...
This.runOnUiThread(function(bundle /*shared obj*/){
                  // etw im Haupt-UI-Thread ausführen ...
});
//...
});

In diesem Code können wir, nachdem wir einen Worker gestartet haben, jeden Code im Worker ausführen lassen, und wenn wir den UI-Thread bedienen müssen (z. B. DOM lesen und schreiben), können wir zur Ausführung zum Haupt-Thread zurückkehren durch this.runOnUiThread.

Wie kann dieser Mechanismus implementiert werden? Schauen Sie sich den folgenden Code an:

Code kopieren Der Code 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 UI-Aufgabe ausführen
          var fn = (new Function("return " ret.__UI_TASK__))();
                 fn(ret.sharedObj);
         }sonst{
                self.sharedObj = ret.sharedObj;
                self._completes[ret.taskId](ret);
}
}
}

WorkerThread.prototype.run = Funktion(Aufgabe, abgeschlossen){
var _task = {__THREAD_TASK__:task.toString(), sharedObj: this.sharedObj, taskId: this._task_id};
This._completes[this._task_id ] = abgeschlossen;
This._worker.postMessage(_task);
}

Der obige Code definiert ein ThreadWorker-Objekt, das einen Web Worker erstellt, der thread.js ausführt, das gemeinsame Objekt SharedObj speichert und die von thread.js zurückgesendeten Nachrichten verarbeitet.

Wenn eine UI_TASK-Nachricht von thread.js zurückgegeben wird, führen Sie die von der Nachricht übergebene Funktion aus, andernfalls führen Sie den vollständigen Rückruf von run aus. Schauen wir uns an, wie thread.js geschrieben ist:

Code kopieren Der Code lautet wie folgt:

onmessage = function(evt){
var data = evt.data;

if(data && data.__THREAD_TASK__){
        var task = data.__THREAD_TASK__;
         Versuchen Sie es{
               var fn = (new Function("return " task))();

var ctx = {
threadSignal: true,
Schlaf: Funktion(Intervall){
                                       ctx.threadSignal = false;
                          setTimeout(_run, Interval);
                 },
                  runOnUiThread: function(task){
PostMessage({__UI_TASK__:task.toString(), sharedObj:data.sharedObj});
                }
            }

Funktion _run(){
                  ctx.threadSignal = true;
              var ret = fn.call(ctx, data.sharedObj);
PostMessage({error:null, returnValue:ret, __THREAD_TASK__:task, sharedObj:data.sharedObj, taskId: data.taskId});
            }

_run(0);

}catch(ex){
PostMessage({error:ex.toString(), returnValue:null, sharedObj: data.sharedObj});
}
}
}

Wie Sie sehen können, empfängt thread.js Nachrichten vom UI-Thread. Die wichtigste davon ist THREAD_TASK, die vom UI-Thread übergebene „Aufgabe“, die vom Arbeitsthread ausgeführt werden muss ist nicht serialisierbar. Der Arbeitsthread analysiert die Zeichenfolge in eine Funktion, um die vom Hauptthread übermittelte Aufgabe auszuführen (beachten Sie, dass das gemeinsam genutzte Objekt sharedObj während der Ausführung übergeben wird). Das Rückgabeergebnis wird über die Nachricht an den UI-Thread übergeben. Schauen wir uns das genauer an. Zusätzlich zum Rückgabewert returnValue wird auch das gemeinsam genutzte Objekt sharedObj zurückgegeben. Da der Worker-Thread und der UI-Thread keine Objekte gemeinsam nutzen, synchronisieren wir die Objekte auf beiden Seiten künstlich Zuweisung (ist dieser Thread sicher? ? Warum? )

Sie sehen, dass der gesamte Prozess nicht kompliziert ist. Nach dieser Implementierung kann dieser ThreadWorker auf die folgenden zwei Arten verwendet werden:

Code kopieren Der Code 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(function(sharedObj){  
            while(this.threadSignal){
                sharedObj.i ;

                this.runOnUiThread(function(sharedObj){
                    W("body ul").appendChild("

  • " sharedObj.i "
  • ");
                    });

                    this.sleep(500);
                }
                return sharedObj.i;
            }, Funktion(r){
                console.log("t2>" r.returnValue ":" r.error);
            });

    这样的用法从形式和语义上来说都让代码具有良好的结构,灵活性和可维护性.

    好了, 关于Web .js (由于Worker需要用服务器测试,我特意在项目中放了一个山寨的httpd.js,是个非常简陋的http服务的js,直接用node就可以跑起来)。

    Stellungnahme:
    Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn