HTML5 mendukung API seperti Web Worker, yang memungkinkan halaman web untuk menjalankan kode multi-threaded dalam situasi yang aman. Namun, pekerja web sebenarnya tunduk pada banyak pembatasan karena tidak dapat benar-benar berbagi data memori dan hanya dapat menggunakan pesan untuk menginformasikan keadaan, sehingga bahkan tidak dapat disebut "multi-threading" dalam arti sebenarnya.
Antarmuka pekerja web sangat tidak nyaman untuk digunakan. Ini pada dasarnya dilengkapi dengan kotak pasir, yang menjalankan file JS independen di kotak pasir, dan berkomunikasi dengan utas utama melalui postmessage dan onMessge:
Salinan kode adalah sebagai berikut:
var pekerja = pekerja baru ("my.js");
var bundle = {pesan: 'halo dunia', id: 1};
worker.postmessage (bundel); // Postmessage dapat melewati objek yang dapat diserialisasi di masa lalu
worker.onMessage = function (evt) {
console.log (evt.data); // Bandingkan objek yang diteruskan kembali dalam pekerja dengan objek di utas utama
console.log (bundel); // {pesan: 'halo dunia', id: 1}
}
Salinan kode adalah sebagai berikut:
// di my.js
onMessage = function (evt) {
var data = evt.data;
data.id ++;
postmessage (data); // {pesan: 'halo dunia', id: 2}
}
Hasilnya dapat ditemukan bahwa ID dari data yang diperoleh di utas telah meningkat, tetapi setelah dilewatkan, ID dalam bundel utas utama tidak diubah. Oleh karena itu, objek yang diteruskan di utas sebenarnya disalin. Dengan cara ini, utas tidak berbagi data, menghindari konflik baca dan tulis, jadi aman. Biaya memastikan keamanan utas adalah membatasi kemampuan untuk mengoperasikan objek utas utama di utas.
Mekanisme multi-threading terbatas seperti itu tidak nyaman untuk digunakan. Tentu saja, kami berharap pekerja dapat mendukung kemampuan untuk membuat kode tampaknya beroperasi multi-threading pada saat yang sama. Misalnya, kode dukungan yang terlihat seperti berikut:
Salinan kode adalah sebagai berikut:
var worker = new threadWorker (bundle /*shared obj* /);
worker.run (fungsi (bundel) {
// lakukan sth di utas pekerja ...
this.runonuithread (function (bundle /*shared obj* /) {
// lakukan sth di utas UI utama ...
});
// ...
});
Dalam kode ini, setelah kita memulai pekerja, kita dapat membiarkan kode apa pun berjalan di pekerja, dan ketika kita perlu mengoperasikan utas UI (seperti membaca dan menulis DOM), kita dapat kembali ke utas utama untuk dieksekusi melalui ini.runonuithread.
Jadi bagaimana menerapkan mekanisme ini? Lihat kode berikut:
Salinan kode adalah sebagai berikut:
function workerThread (sharedoBj) {
this._worker = pekerja baru ("thread.js");
this._completes = {};
this._task_id = 0;
this.sharedobj = sharedobj;
var self = ini;
this._worker.onMessage = function (evt) {
var ret = evt.data;
if (ret .__ ui_task __) {
// jalankan tugas UI
var fn = (fungsi baru ("return"+ret .__ ui_task __)) ();
fn (ret.sharedobj);
}kalau tidak{
self.sharedobj = ret.sharedobj;
self._completes [ret.taskid] (ret);
}
}
}
Workerthread.prototype.run = function (tugas, lengkap) {
var _task = {__thread_task __: task.toString (), sharedoBj: this.sharedobj, TaskId: this._task_id};
this._completes [this._task_id ++] = Lengkap;
this._worker.postmessage (_task);
}
Kode di atas mendefinisikan objek ThreadWorker. Objek ini membuat pekerja web yang menjalankan thread.js, menyimpan objek bersama SharedOBJ, dan memproses pesan yang dikirim kembali oleh thread.js.
Jika pesan UI_Task ditransmisikan kembali di Thread.js, lalu jalankan fungsi yang dilewati oleh pesan ini. Kalau tidak, jalankan panggilan balik lengkap dari Run, mari kita lihat bagaimana Thread.js ditulis:
Salinan kode adalah sebagai berikut:
onMessage = function (evt) {
var data = evt.data;
if (data && data .__ thread_task __) {
var Task = data .__ thread_task__;
mencoba{
var fn = (fungsi baru ("return"+Task)) ();
var ctx = {
ThreadSignal: Benar,
Sleep: function (interval) {
ctx.threadSignal = false;
setTimeout (_run, interval);
},
runonuithread: function (tugas) {
PostMessage ({__ UI_Task __: Task.ToString (), ShareDoBj: Data.SharedObj});
}
}
fungsi _run () {
ctx.threadSignal = true;
var ret = fn.call (ctx, data.sharedobj);
PostMessage ({error: null, returnValue: ret, __thread_task __: tugas, sharedoBj: data.sharedobj, TaskId: data.taskid});
}
_run (0);
} catch (ex) {
PostMessage ({error: ex.toString (), returnValue: null, sharedoBj: data.sharedobj});
}
}
}
Dapat dilihat bahwa thread.js menerima pesan dari utas UI, yang paling penting adalah Thread_Task, yang merupakan "tugas" yang dilewati oleh utas UI yang perlu dieksekusi oleh utas pekerja. Karena fungsi tidak dapat diserialisasi, ia dilewatkan string. Utas pekerja mem -parsing string ke dalam suatu fungsi untuk menjalankan tugas yang dikirimkan oleh utas utama (perhatikan bahwa objek bersama ShareDoBJ dilewatkan dalam tugas). Setelah eksekusi selesai, hasil pengembalian akan diteruskan ke utas UI melalui pesan. Mari kita lihat lebih dekat pada objek bersama ShareDoBJ di samping Value ReturnValue yang kembali. Saat berlalu, karena utas pekerja dan utas UI tidak berbagi objek, kami secara artifisial menyinkronkan objek di kedua sisi melalui penugasan (apakah utas ini aman? Mengapa?)
Anda dapat melihat bahwa seluruh proses tidak rumit. Setelah implementasi ini, threadworker ini dapat memiliki dua kegunaan berikut:
Salinan kode adalah sebagai berikut:
var t1 = workerThread baru ({i: 100} /*dibagikan obj* /);
setInterval (function () {
t1.run (function (sharedoBj) {
return sharedobj.i ++;
},
function (r) {
console.log ("t1>" + r.returnValue + ":" + r.error);
}
);
}, 500);
var t2 = workerThread baru ({i: 50});
t2.run (function (sharedoBj) {
while (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);
});
Penggunaan ini memberikan kode struktur, fleksibilitas, dan pemeliharaan yang baik dalam bentuk dan istilah semantik.
Oke, itu saja untuk diskusi tentang penggunaan pekerja web. Siswa yang tertarik dapat melihat proyek ini: https://github.com/akira-cn/workerthread.js (karena pekerja perlu menggunakan pengujian server, saya khususnya meletakkan copycat httpd.js di proyek, yang merupakan layanan http yang sangat sederhana, dan Anda dapat menjalankannya secara langsung).