HTML5 admite API como Web Worker, lo que permite que las páginas web ejecuten código múltiple en una situación segura. Sin embargo, el trabajador web está en realidad sujeto a muchas restricciones porque realmente no puede compartir datos de memoria y solo puede usar mensajes para informar el estado, por lo que ni siquiera se puede llamar "múltiples subprocesos" en el verdadero sentido.
La interfaz de Web Worker es muy inconveniente de usar. Básicamente viene con un sandbox, que ejecuta un archivo JS independiente en el sandbox, y se comunica con el hilo principal a través de PostMessage y OnMessge:
La copia del código es la siguiente:
var trabajador = nuevo trabajador ("my.js");
var bundle = {Mensaje: 'Hello World', id: 1};
trabajador.postMessage (paquete); // Postmessage puede pasar un objeto serializable en el pasado
trabajador.onmessage = function (evt) {
console.log (evt.data); // Compare los objetos que se transmiten en el trabajador con objetos en el hilo principal
console.log (paquete); // {Mensaje: 'Hello World', id: 1}
}
La copia del código es la siguiente:
// en my.js
onMessage = function (evt) {
var data = evt.data;
data.id ++;
postmessage (datos); // {Mensaje: 'Hello World', Id: 2}
}
El resultado se puede encontrar que la ID de los datos obtenidos en el hilo ha aumentado, pero después de que se retira, la ID en el paquete del hilo principal no cambia. Por lo tanto, el objeto pasado en el hilo realmente se copia. De esta manera, el hilo no comparte los datos, evitando conflictos de lectura y escritura, por lo que es seguro. El costo de garantizar la seguridad del subproceso es limitar la capacidad de operar objetos de hilo principales en el hilo.
Tal mecanismo limitado de subprocesos múltiples es inconveniente de usar. Por supuesto, esperamos que los trabajadores puedan apoyar la capacidad de hacer que el código parezca operar múltiples subprocesos al mismo tiempo. Por ejemplo, código de soporte que se parece al siguiente:
La copia del código es la siguiente:
var trabajador = new Threadworker (Bundle /*compartido obj* /);
trabajador.run (function (paquete) {
// hacer sth en el hilo de trabajadores ...
this.runonuithread (function (bundle /*compartido obj* /) {
// Do sth en el hilo de la interfaz de usuario principal ...
});
// ...
});
En este código, después de comenzar a un trabajador, podemos dejar que cualquier código se ejecute en el trabajador, y cuando necesitemos operar el hilo de la interfaz de usuario (como leer y escribir el DOM), podemos volver al hilo principal para ejecutar a través de esto.
Entonces, ¿cómo implementar este mecanismo? Mira el siguiente código:
La copia del código es la siguiente:
function 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 retir = evt.data;
if (ret .__ ui_task __) {
// ejecutar en la tarea de interfaz de usuario
var fn = (nueva función ("return"+ret .__ ui_task __)) ();
fn (ret.sharedobj);
}demás{
self.sharedobj = ret.sharedobj;
self._completes [ret.taskid] (ret);
}
}
}
Workerthread.prototype.run = function (tarea, completo) {
var _task = {__thread_task __: task.ToString (), sharedObj: this.sharedobj, taskID: this._task_id};
this._completes [this._task_id ++] = completo;
this._worker.postMessage (_task);
}
El código anterior define un objeto Threadworker. Este objeto crea un trabajador web que ejecuta Thread.js, guarda el objeto compartido compartido y procesa los mensajes enviados por Thread.js.
Si se transmite un mensaje UI_Task en Thread.js, ejecute la función pasada por este mensaje. De lo contrario, ejecute la devolución de llamada completa de Run, veamos cómo se escribe Thread.js:
La copia del código es la siguiente:
onMessage = function (evt) {
var data = evt.data;
if (data && data .__ thread_task __) {
var tarea = data .__ thread_task__;
intentar{
var fn = (nueva función ("return"+tarea)) ();
var ctx = {
ThreadSignal: verdadero,
dormir: función (intervalo) {
ctx.threadSignal = false;
setTimeOut (_run, intervalo);
},
runonuithread: function (tarea) {
PostMessage ({__ ui_task __: task.ToString (), sharedObj: data.sharedObj});
}
}
función _run () {
ctx.threadSignal = true;
var retir = fn.call (ctx, data.sharedobj);
PostMessage ({Error: null, returnValue: ret, __thread_task __: tarea, sharedobj: data.sharedobj, tareas: data.taskid});
}
_run (0);
} catch (ex) {
PostMessage ({Error: ex.ToString (), returnValue: null, sharteObj: data.sharedobj});
}
}
}
Se puede ver que Thread.js recibe mensajes de los hilos de interfaz de usuario, el más importante de los cuales es Thread_Task, que es la "tarea" aprobada por los hilos de interfaz de usuario que deben ser ejecutados por el hilo del trabajador. Dado que la función no es serializable, se pasa una cadena. El hilo del trabajador analiza la cadena en una función para ejecutar las tareas enviadas por el hilo principal (tenga en cuenta que el objeto compartido compartido se pasa en la tarea). Después de completar la ejecución, el resultado de devolución se pasará al hilo de la interfaz de usuario a través del mensaje. Echemos un vistazo más de cerca al objeto compartido SharedObj además del valor de retorno returnValue. Al pasar, dado que el hilo del trabajador y el hilo de la interfaz de usuario no comparten el objeto, sincronizamos artificialmente los objetos en ambos lados a través de la tarea (¿es seguro este hilo?)
Puede ver que todo el proceso no es complicado. Después de esta implementación, este subprocesador puede tener los siguientes dos usos:
La copia del código es la siguiente:
var t1 = new WorkerThread ({i: 100} /*obj* /);
setInterval (function () {
t1.run (function (sharteObj) {
return sharedobj.i ++;
},
función (r) {
console.log ("t1>" + r.returnvalue + ":" + r.error);
}
);
}, 500);
var t2 = new WorkerThread ({i: 50});
t2.run (function (sharteObj) {
while (this.threadsignal) {
Sharedobj.i ++;
this.runonuithread (function (sharteObj) {
W ("Body Ul"). AppendChild ("<li>"+SharedObj.i+"</li>");
});
this.sleep (500);
}
regresar SharedObj.i;
}, función (r) {
console.log ("t2>" + r.returnvalue + ":" + r.error);
});
Este uso le da al código una buena estructura, flexibilidad y mantenimiento en términos de forma y semántica.
Bien, eso es todo para la discusión sobre el uso de la trabajadora web. Los estudiantes interesados pueden echar un vistazo a este proyecto: https://github.com/akira-cn/workerthread.js (dado que el trabajador necesita usar las pruebas de servidor, especialmente pongo un copycat httpd.js en el proyecto, que es un servicio HTTP muy simple JS, y puede ejecutarlo con Node directamente).