O HTML5 suporta APIs como o Web Worker, permitindo que as páginas da Web executem código multithread em uma situação segura. No entanto, o Web Worker está realmente sujeito a muitas restrições porque não pode compartilhar dados de memória e só pode usar mensagens para informar o estado, por isso não pode ser chamado de "multi-threading" no sentido verdadeiro.
A interface do Web Worker é muito inconveniente de usar. Basicamente, ele vem com uma caixa de areia, que executa um arquivo JS independente na caixa de areia e se comunica com o tópico principal através da pós -maquiagem e OnMessge:
A cópia do código é a seguinte:
var trabalhador = novo trabalhador ("my.js");
var bundle = {message: 'Hello World', id: 1};
trabalhador.PostMessage (pacote); // Postmessage pode passar por um objeto serializável no passado
trabalhador.onmessage = function (evt) {
console.log (evt.data); // Compare objetos transmitidos ao trabalhador com objetos no tópico principal
console.log (pacote); // {message: 'Hello World', Id: 1}
}
A cópia do código é a seguinte:
// em meu.js
onMessage = function (EVT) {
var dados = evt.data;
data.id ++;
pós -maquiagem (dados); // {message: 'Hello World', id: 2}
}
Pode -se descobrir o resultado que o ID dos dados obtidos no encadeamento aumentou, mas depois de serem transmitidos, o ID no pacote do encadeamento principal não é alterado. Portanto, o objeto passado no encadeamento é realmente copiado. Dessa forma, o encadeamento não compartilha os dados, evitando conflitos de leitura e gravação, por isso é seguro. O custo de garantir a segurança do encadeamento é limitar a capacidade de operar objetos principais do encadeamento no encadeamento.
Um mecanismo de threading tão limitado é inconveniente de usar. Obviamente, esperamos que o trabalhador possa apoiar a capacidade de fazer com que o código pareça operar multi-threading ao mesmo tempo. Por exemplo, o código de suporte que se parece com o seguinte:
A cópia do código é a seguinte:
var trabalhador = novo ThreadWorker (pacote /*obj compartilhado* /);
trabalhador.run (função (pacote) {
// Faça sth no tópico de trabalhador ...
this.RunonuithRead (função (pacote /*compartilhado obj* /) {
// Faça sth no tópico principal da interface do usuário ...
});
// ...
});
Nesse código, depois de iniciarmos um trabalhador, podemos deixar qualquer código executado no trabalhador e, quando precisamos operar o thread da interface do usuário (como ler e escrever o DOM), podemos retornar ao thread principal para executá -lo.
Então, como implementar esse mecanismo? Veja o seguinte código:
A cópia do código é a seguinte:
função 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 __) {
// Execute na tarefa da interface do usuário
var fn = (nova função ("return"+ret .__ ui_task __)) ();
fn (ret.sharedobj);
}outro{
self.sharedobj = ret.sharedobj;
self._completes [ret.taskid] (ret);
}
}
}
Trabalhadorthread.prototype.run = function (tarefa, completa) {
var _Task = {__Thread_Task __: Task.ToString (), SharedObj: this.Sharedobj, TaskId: this._task_id};
this._completes [this._task_id ++] = completo;
this._worker.postMessage (_Task);
}
O código acima define um objeto ThreadWorker. Este objeto cria um trabalhador da web executando thread.js, salva o objeto compartilhado sharedobj e processa as mensagens enviadas de volta pelo thread.js.
Se uma mensagem UI_TASK for transmitida de volta no Thread.js, execute a função passada por esta mensagem. Caso contrário, execute o retorno de chamada completo do RUN, vamos ver como Thread.js está escrito:
A cópia do código é a seguinte:
onMessage = function (EVT) {
var dados = evt.data;
if (data && data .__ Thread_task __) {
var tarefa = dados .__ Thread_task__;
tentar{
var fn = (nova função ("return"+tarefa)) ();
var ctx = {
Threadsignal: verdadeiro,
Sono: function (intervalo) {
ctx.ThreadSignal = false;
setTimeout (_run, intervalo);
},
runonuithread: function (tarefa) {
PostMessage ({__ UI_Task __: Task.ToString (), SharedOBJ: Data.Sharedobj});
}
}
função _run () {
ctx.ThreadSignal = true;
var ret = fn.call (ctx, data.sharedobj);
PostMessage ({Erro: NULL, ReturnValue: RET, __THREAD_TASK __: Tarefa, SharedObj: Data.Sharedobj, TaskId: Data.Taskid});
}
_run (0);
} catch (ex) {
PostMessage ({Error: Ex.ToString (), ReturnValue: NULL, SharedObj: Data.Sharedobj});
}
}
}
Pode -se ver que o Thread.js recebe mensagens de threads da interface do usuário, o mais importante dos quais é Thread_Task, que é a "tarefa" passada pelos threads da interface do usuário que precisam ser executados pelo thread do trabalhador. Como a função não é serializável, ela é passada uma string. O encadeamento do trabalhador analisa a string em uma função para executar as tarefas enviadas pelo encadeamento principal (observe que o objeto compartilhado sharedobj é aprovado na tarefa). Após a conclusão da execução, o resultado de retorno será passado para o tópico da interface do usuário através da mensagem. Vamos dar uma olhada mais de perto no objeto compartilhado sharedobj, além do valor de retorno de retorno. Ao passar de volta, como o tópico do trabalhador e o tópico da interface do usuário não compartilham o objeto, sincronizamos artificialmente os objetos de ambos os lados através da atribuição (este tópico é seguro? Por quê?)
Você pode ver que todo o processo não é complicado. Após esta implementação, este threadworker pode ter os dois usos a seguir:
A cópia do código é a seguinte:
var t1 = new WorkerThread ({i: 100} /*obj compartilhado* /);
setInterval (function () {
t1.run (função (sharedobj) {
return sharedobj.i ++;
},
função (r) {
console.log ("t1>" + r.returnValue + ":" + r.error);
}
);
}, 500);
var T2 = new WorkerThread ({i: 50});
t2.run (função (sharedobj) {
while (this.threadSignal) {
sharedobj.i ++;
this.Runonuithread (function (sharedobj) {
W ("corpo ul"). AppendChild ("<li>"+sharedobj.i+"</li>");
});
this.sleep (500);
}
return sharedobj.i;
}, function (r) {
console.log ("t2>" + r.returnValue + ":" + r.error);
});
Esse uso fornece ao código boa estrutura, flexibilidade e manutenção em termos de forma e semânticos.
Ok, isso é tudo para a discussão sobre o uso do Web Worker. Os alunos interessados podem dar uma olhada neste projeto: https://github.com/akira-cn/workerthread.js (Como o trabalhador precisa usar o teste do servidor, coloco especialmente um httpd.js de imersão no projeto, que é um serviço HTTP muito simples e você pode executá-lo diretamente).