Javascript único thread
O encadeamento único do JavaScript está relacionado ao seu objetivo. Como linguagem de script de navegador, o principal objetivo do JavaScript é interagir com os usuários e operar o DOM. Isso determina que só pode ser um único rosqueado, caso contrário, causará problemas de sincronização muito complexos. Por exemplo, suponha que o JavaScript tenha dois threads ao mesmo tempo, um thread adiciona conteúdo em um determinado nó DOM e o outro thread exclui esse nó, qual encadeamento o navegador deve tomar neste momento? Portanto, para evitar a complexidade, o JavaScript é um único thread desde o nascimento, que se tornou a característica central desse idioma e não mudará no futuro.
Tarefas de fila
Trebo único significa que todas as tarefas precisam ser filadas e a tarefa anterior será executada antes que a próxima tarefa seja executada. Se a tarefa anterior levar muito tempo, a próxima tarefa terá que esperar.
Driver de evento assíncrono
Muitos comportamentos no navegador são assincronizados, como: Evento de clique do mouse, evento de arrasto de tamanho de janela, evento de gatilho do timer, retorno de chamada de conclusão xmlHttPrequest, etc. Quando ocorre um evento assíncrono, ele entra na fila do evento. O navegador possui um loop de mensagem grande interno, loop de eventos, que pesquisará grandes filas de eventos e eventos de processo. Por exemplo, o navegador está atualmente ocupado processando o evento OnClick e, em seguida, ocorre outro evento (como Window Onsize), e esse evento assíncrono é colocado na fila de eventos e aguarda o processamento. Este evento será executado apenas quando o processamento anterior for concluído e for gratuito.
Loop de eventos
JavaScript é um único thread, mas o navegador não é um único thread
O navegador terá pelo menos alguns dos seguintes processos
1. Tópico de renderização da GUI do navegador
2. Tópico do motor JavaScript
3. Tópico de gatilho cronometrado do navegador
4. Evento do navegador Greia de gatilhos
5. Browser Http Afternou
Como o mecanismo JavaScript é um thread único, o código é pressionado pela primeira vez na fila e depois executado pelo mecanismo de uma maneira primeira em primeiro lugar. Funções de manuseio de eventos e funções de execução do timer também serão colocadas nesta fila e, em seguida, usarão um loop infinito para extrair continuamente as funções do chefe da equipe para executar. Este é o loop de eventos.
Em resumo, o JS é um thread único, mas o navegador é multi-thread. Ao encontrar coisas assíncronas, o navegador colocará o retorno de chamada assíncrono no loop do evento. Quando o tópico JS não estiver ocupado, leia o loop do evento.
Princípio do timer
Como usar o timer
setTimeout (FN, atraso)
setInterval (fn, atraso)
FN é uma função ou uma string, o atraso é o tempo de atraso, a unidade é milissegundos
Há as seguintes coisas a serem observadas
1. Embora o FN possa ser uma corda, nunca é recomendável usá -la assim.
2. Se houver essa função no FN, isso apontará para a janela ao executar.
Se você entender bem o lixo único e o loop de eventos do JS, o princípio do timer será fácil de entender.
Se um temporizador estiver definido, quando o tempo de atraso for atingido, o navegador colocará o evento de execução atrasado no loop do evento. Quando o tempo acabar, se o tópico JS estiver ocioso, ele será executado (para que a precisão do timer seja imprecisa)
Eu li um artigo sobre a diferença entre o setTimeout e o SetInterval que sempre as funções de pesquisa. O código é o seguinte
A cópia do código é a seguinte:
setTimeout (function () {
setTimeout (Argumments.Callee, 100)
}, 100)
setInterval (function () {}, 1000)
O significado geral do artigo é que o setTimeout inicia o próximo temporizador após a execução da função de retorno de chamada, para que ele seja executado em intervalos, enquanto o setInterval é executado o tempo todo. Se você encontrar um thread JS que continue executando, poderá adicionar vários retornos de chamada no loop de eventos. Quando o thread JS não estiver ocupado, várias execuções serão executadas uma após a outra.
Após o teste, verificou -se que o SetInterval está em um determinado intervalo, não importa em IE, FF, Chrome, Opera e Safari.
O código de teste é o seguinte
A cópia do código é a seguinte:
setInterval (function () {
xx.innerhtml = xx.innerhtml+1;
}, 100);
for (var i = 0; i <6000000; i ++) {
xx.offsetWidth
}
setTimeout (function () {
depurador;
}, 10)
Quando pontos de interrupção ainda são impressos apenas 1
Problemas de precisão do timer
Por causa do tópico único do JS, se você encontrar ocupação, o timer será definitivamente impreciso e definitivamente será mais longo. Isso parece ser insolúvel, sem solução.
Outro problema de precisão é o intervalo mínimo Settimeout (Fun, 0)
Quando o tópico JS não está ocupado, é impossível executar imediatamente após 0 segundos. Sempre há um intervalo mínimo e cada navegador ainda é diferente. Isso não foi testado.
Eu li um artigo sobre o padrão do W3C. A execução mínima do tempo do timer é de 4ms. Não há como verificar a fonte se você não conseguir encontrá -la! ! !
Algumas otimizações relacionadas a temporizadores
Ainda existem algumas otimizações ao fazer temporizadores
1. Por exemplo, se você ligar a janela.OnResize, o gatilho será muito frequente quando o navegador estiver em zoom, para que você possa atrasar a execução. Quando a próxima execução for limpa, reduzirá a execução frequente.
O pseudo-código é o seguinte
A cópia do código é a seguinte:
Var Timer;
função r () {
ClearTimeout (timer);
Timer = setTimeout (function () {
// Faça algo
}, 150);
}
2. Quando a barra de rolagem é puxada para baixo, também é um pouco. Por exemplo, o preguiçoso da imagem também deve ter um cronômetro para evitar cálculos excessivos.
3. Quando há vários lugares onde os temporizadores são necessários, você pode mesclá -los em um cronômetro. O intervalo de tempo é o menor. Em seguida, a função de retorno de chamada que precisa ser executada é recheada na matriz. Quando o intervalo de tempo for atingido, itera através da matriz para executar.
Uma pequena demonstração
A cópia do código é a seguinte:
<! Doctype html>
<html>
<head>
<meta charset = "utf-8" />
<estilo>
.Wrap {Width: 80%; margem: 30px automático; borda: 1px sólido #ccc; preenchimento: 20px;}
.c {borda: 1px sólido #ccc; Altura: 30px; Margin-Bottom: 20px;}
</style>
</head>
<Body>
<div id = "xx"> </div>
<div>
<div id = "A1"> 0 </div>
<div id = "A2"> 0 </div>
<div id = "A3"> 0 </div>
<div id = "a4"> 0 </div>
</div>
<script src = "http://static.paipaiimg.com/paipai_h5/js/ttj/zepto.min.js"> </script>
<script type = "text/javascript">
var tempo de execução = {
Opções: {
Etapa: 1000
},
retornos de chamada: [],
addCallbacks: [],
Iniciar: Falso,
Timer: nulo,
estender: function () {
VAR Target = Argumentos [0] || {}, i = 1, comprimento = argumentos.length, opções;
if (typeof alvo! = "Object" && typeof Target! = "Função")
Target = {};
para (; i <comprimento; i ++)
if ((opções = argumentos [i])! = nulo)
para (Var Nome in Options) {
var cópia = opções [nome];
if (Target === cópia)
continuar;
if (cópia! == indefinido)
Target [nome] = cópia;
}
alvo de retorno;
},
init: function (opções) {
$ .extend (this, this.options, opções || {});
},
Add: function (diversão, opções) {
opções = opções || {};
this.addcallbacks.push ({
Diversão: Diversão,
StartTime: new Date (). gettime (),
Etapa: options.Tep || this.tep,
I: 1
});
var self = this;
if (! this.start) {
this.callbacks = [fun];
this.start = true;
this.startTime = new Date (). getTime ();
this.timer = setInterval (function () {
self.done ();
}, this.tep);
}
},
feito: function () {
VAR ROTLBACKS = this.Callbacks,
eu = isso,
newarr = [];
$ .ECH (retornos de chamada, função (i, obj) {
if (obj.Step == self.Tep) {
obj.fun ();
}outro{
if (obj.i == obj.Step/self.Step) {
if ((new Date (). gettime ())-obj.starttime> obj.step*2/3) {
obj.fun ();
}
obj.i = 1;
}outro{
obj.i = obj.i + 1;
}
}
});
$ .ECH (this.addcallbacks, function (i, obj) {
if (obj.Step == self.Tep) {
if ((new Date (). gettime ())-obj.starttime> obj.step*2/3) {
obj.fun ();
retorno de chamada.push (obj);
}outro{
newarr.push (obj);
}
}outro{
obj.i = obj.i + 1;
retorno de chamada.push (obj);
}
});
this.addcallbacks = newarr;
},
claro: function () {
ClearInterval (this.timer);
}
}
RUNTIME.InIT ();
RUNTIME.ADD (function () {
a1.innerhtml = ~~ a1.innerhtml+1;
});
RUNTIME.ADD (function () {
a2.innerhtml = ~~ a2.innerhtml+1;
}, {step: 2000});
RUNTIME.ADD (function () {
a3.innerhtml = ~~ a3.innerhtml+1;
}, {step: 4000});
RUNTIME.ADD (function () {
a4.innerhtml = ~~ a4.innerhtml+1;
}, {Etapa: 8000});
</script>
</body>
</html>
Você tem alguma ideia sobre o cronômetro JavaScript? Deixe -me uma mensagem se tiver alguma dúvida.