De qualquer forma, desde que a atualização não se reproduza após um erro de JavaScript, o usuário pode resolver o problema refrescante e o navegador não falhará, e tudo bem se não tiver acontecido. Essa suposição era verdadeira antes que o aplicativo de página única se tornasse popular. O aplicativo atual é extremamente complexo após a execução por um período de tempo. Você não retrabalharia completamente as operações anteriores? Portanto, ainda é necessário capturar e analisar essas informações de exceção e, em seguida, podemos modificar o código para evitar afetar a experiência do usuário.
Como pegar exceções Nós nos escrevemos throw new Error()
que certamente podemos capturar se quisermos capturar, porque sabemos muito bem onde throw
está escrito. No entanto, exceções que ocorrem ao chamar a API do navegador não são necessariamente tão fáceis de capturar. Para o primeiro, também podemos pegá-lo através try-catch
, para o último, devemos ouvir exceções globais e depois pegá-lo.
Se algumas APIs do navegador forem conhecidas por lançar exceções, precisamos colocar a chamada em try-catch
para evitar todo o programa que entra em um estado ilegal devido a erros. Por exemplo, window.localStorage
é uma API tal.
try {
LocalStorage.SetItem ('Date', Date.now ());
} catch (erro) {
repórterror (erro);
}
Outro cenário aplicável try-catch
comum são os retornos de chamada. Como o código da função de retorno de chamada é incontrolável, não sabemos o quão bom é o código e se outras APIs que lançam exceções serão chamadas. Para não fazer com que outros códigos sejam executados após ligar para o retorno de chamada devido a erros de retorno de chamada, é necessário colocar a chamada de volta no try-catch
.
listeners.forEach(function(listener) {
tentar {
ouvinte();
} catch (erro) {
repórterror (erro);
}
});
Para lugares que try-catch
não podem cobrir, se ocorrer uma exceção, ele só poderá ser capturado pela window.onerror
.
window.onerror =
função (errorMessage, scripturi, linho) {
repórterror ({
Mensagem: errorMessage,
Script: scripturi,
Linha: Number linear
});
}
Cuidado para não ser inteligente e usar window.addEventListener
ou window.attachEvent
para ouvir a window.onerror
. Muitos navegadores implementam apenas window.onerror
, ou apenas a implementação window.onerror
é padrão. Considerando que o rascunho padrão também define window.onerror
, precisamos usar window.onerror
.
Suponha que tenhamos uma função reportError
para coletar exceções capturadas e enviá-las para armazenamento do lado do servidor em lotes para consulta e análise, que informações queremos coletar? Informações mais úteis incluem: Tipo de erro ( name
), mensagem de erro ( message
), endereço do arquivo de script ( script
), número da linha ( line
), número da coluna ( column
) e rastreamento de pilha ( stack
). Se uma exceção for capturada através try-catch
, todas essas informações estarão no objeto Error
(suportado pelos navegadores mainstream), para que reportError
também possa coletar essas informações. Mas se for capturado através do window.onerror
, todos sabemos que essa função de evento possui apenas 3 parâmetros, portanto, as informações inesperadas desses 3 parâmetros serão perdidas.
Se o objeto Error
for criado por nós mesmos, error.message
será controlado por nós. Basicamente, o que message
em error.message
window.onerror
(O navegador realmente tornará um pouco modificado, como adicionar 'Uncaught Error: '
prefixo.) Portanto, podemos serializar os atributos com os quais estamos preocupados (como JSON.Stringify
) e armazená -los em error.message
e depois lidos eles em window.onerror
Obviamente, isso é limitado a objetos Error
que nos criamos.
Os fabricantes de navegadores também sabem as restrições às quais as pessoas estão sujeitas ao usar window.onerror
, então começam a adicionar novos parâmetros ao window.onerror
. Considerando que apenas os números de linha e nenhum número de colunas parecem ser muito simétricos, ou seja, adicionou os números da coluna e os colocou no quarto parâmetro. No entanto, o que todos estão mais preocupados é se eles podem obter a pilha completa, então o Firefox disse que seria melhor colocar a pilha no quinto parâmetro. Mas o Chrome disse que seria melhor colocar todo o objeto Error
no quinto parâmetro, e você pode ler quaisquer atributos, incluindo atributos personalizados. Como resultado, o Chrome está se movendo mais rápido, uma nova assinatura window.onerror
.
Regularidade de atributoswindow.onerror = function(
errorMessage,
scripturi,
Linho, número,
columnNumber,
erro
) {
if (erro) {
repórterror (erro);
} outro {
repórterror ({
Mensagem: errorMessage,
Script: scripturi,
linha: linenumber,
Coluna: columnNumber
});
}
}
Os script
dos atributos do objeto Error
Error
que discutimos antes filename
baseados nos métodos de nomeação do Chrome. Portanto, também precisamos de uma função especial para normalizar o objeto Error
, ou seja, para mapear nomes de atributos diferentes para um nome de atributo unificado. Para práticas específicas, consulte este artigo. Embora a implementação do navegador seja atualizada, não será muito difícil para os seres humanos manter uma tabela de mapeamento.
Semelhante é o formato do rastreamento stack
. Essa propriedade salva as informações da pilha de uma exceção quando ocorre na forma de texto simples. identifier
script
line
column
Se você também encontrou um erro com a mensagem 'Script error.'
O motivo dessa restrição de segurança é o seguinte: suponha que o HTML retornado por um banqueiro on-line após o login seja diferente do HTML visto por um usuário anônimo, um site de terceiros pode colocar o URI deste banco on-line script.src
atributo script.src
. Obviamente, o HTML não pode ser analisado como JS, portanto o navegador lançará uma exceção e este site de terceiros pode determinar se o usuário está conectado analisando a localização da exceção. Por esse motivo, o navegador filtra todas as exceções lançadas por diferentes arquivos de script de origem, deixando apenas uma mensagem inalterada como 'Script error.'
Para sites de uma certa escala, é normal que os arquivos de script sejam colocados em CDNs e diferentes fontes são colocadas. Agora, mesmo se você criar um pequeno site, estruturas comuns, como jQuery e backbone, podem fazer referência diretamente à versão do CDN público para acelerar o downloads do usuário. Portanto, essa restrição de segurança causa alguns problemas, causando as informações de exceção que coletam do Chrome e do Firefox para ser inútil 'Script error.'
Se você deseja ignorar essa restrição, apenas verifique se o arquivo de script e a página são iguais. Mas a colocação de arquivos de script em servidores que não são acelerados pela CDN reduziam a velocidade de download do usuário? Uma solução é continuar colocando o arquivo de script no CDN, use XMLHttpRequest
para baixar o conteúdo de volta através do CORS e, em seguida, crie uma tag <script>
para injetar -a na página. O código incorporado na página é obviamente a mesma origem.
É simples dizer, mas há muitos detalhes a serem implementados. Para dar um exemplo simples:
<script src="http://cdn.com/step1.js"></script>
<Cript>
(função step2 () {}) ();
</script>
<script src = "http://cdn.com/step3.js"> </script>
Todos sabemos que, se houver dependências na etapa 1, passo2 e etapa3, ele deverá ser executado estritamente nessa ordem, caso contrário, poderá ocorrer um erro. O navegador pode solicitar arquivos da etapa 1 e 3 em paralelo, mas o pedido é garantido quando executado. Se obtivermos o conteúdo do arquivo da Etapa 1 e da Etapa 3 usando XMLHttpRequest
, precisamos garantir a ordem correta própria. Além disso, não se esqueça da Etapa 2.
Se já tivermos um conjunto completo de ferramentas para gerar tags <script>
para diferentes páginas no site, precisamos ajustar esse conjunto de ferramentas para fazer alterações nas tags <script>
:
<script>
ScheduleRemoteScript ('http://cdn.com/step1.js');
</script>
<Cript>
ScheduleInLininScript (Código da função () {
(função step2 () {}) ();
});
</script>
<Cript>
ScheduleRemoteScript ('http://cdn.com/step3.js');
</script>
Precisamos implementar as duas funções do scheduleRemoteScript
e scheduleInlineScript
e garantir que elas sejam definidas antes da primeira tag <script>
que referencia o arquivo de script externo e, em seguida, as tags <script>
restantes serão reescritas no formulário acima. Observe que a função step2
que foi executada imediatamente foi colocada em uma função code
maior. A função code
não será executada, é apenas um contêiner, para que o código Etapa 2 original possa ser retido sem escapar, mas não será executado imediatamente.
Em seguida, precisamos implementar um mecanismo completo para garantir que o conteúdo do arquivo baixado pelo scheduleRemoteScript
com base no endereço e o código obtido diretamente pelo scheduleInlineScript
possa ser executado um por um na ordem correta. Não vou dar o código detalhado aqui.
A obtenção de conteúdo através do CORS e a injeção de código na página pode interromper as restrições de segurança, mas introduzirá um novo problema, ou seja, os conflitos de número da linha. Originalmente, o arquivo de script exclusivo pode ser localizado através do error.script
e, em seguida, o número da linha exclusivo pode ser localizado através do error.line
. Agora, como são <script>
os códigos incorporados na página, várias tags <script>
não podem ser distinguidas pelo error.script
. .
Para evitar conflitos de número de linha, podemos desperdiçar alguns números de linha para que os intervalos de número da linha usados pelo código real em cada tag <script>
não se sobreponham entre si. Por exemplo, assumindo que o código real em cada tag <script>
não exceda 1000 linhas, posso deixar o código na primeira tag <script>
pegue a linha 11000 e deixe o segundo <script>
tag o código no código Ocupa a linha 10012000 (1000 linhas vazias inseridas antes da inserção), o código da terceira tag <script>
ocupa a linha 20013000 (2000 linha vazia inserida antes da inserção) e assim por diante. Em seguida, usamos o atributo data-*
para registrar essas informações para facilitar a verificação de volta.
<script
data-src = "http://cdn.com/step1.js"
Data-line-start = "1"
>
// Código para a etapa 1
</script>
<Script Data-line-start = "1001">
// '/n' * 1000
// Código para a etapa 2
</script>
<script
data-src = "http://cdn.com/step3.js"
Data-line-start = "2001"
>
// '/n' * 2000
// Código para a etapa 3
</script>
Após esse processamento, se um error.line
de erro.Line for 3005
, isso significa que o error.script
real.script deve ser 'http://cdn.com/step3.js'
, enquanto o error.line
real.line deve ser 5
. Podemos concluir esse número de linha reversa na função reportError
mencionada anteriormente.
Obviamente, como não podemos garantir que cada arquivo de script possui apenas 1000 linhas, também é possível que alguns arquivos de script sejam significativamente inferiores a 1000 linhas, portanto, não há necessidade de alocar fixamente 1000 linhas para cada tag <script>
. Podemos alocar intervalos com base no número real de linhas de script, apenas garantir que os intervalos usados por cada tag <script>
não se sobreponham.
As restrições de segurança impostas pelos navegadores sobre o conteúdo de diferentes fontes não se limitam à tag <script>
. Como XMLHttpRequest
pode romper essa limitação através dos CORS, por que os recursos são referenciados diretamente através de tags não permitidas? Isso certamente está bem.
A limitação de se referir a diferentes arquivos de script de origem para <script>
também se aplica a referir -se a diferentes arquivos de imagem de origem para <img>
. Se uma tag <img>
for uma fonte diferente, uma vez usado ao desenhar <canvas>
, o <canvas>
se tornará um estado somente de gravação, garantindo que o site não possa roubar dados de imagem não autorizados de diferentes fontes através do JavaScript. Posteriormente, a tag <img>
resolveu esse problema introduzindo o atributo crossorigin
. Se crossorigin="anonymous"
for usado, é equivalente aos cors anônimos;
Como a tag <img>
pode fazer isso, por que a tag <script>
não pode fazer isso? Portanto, o fabricante do navegador adicionou o mesmo atributo crossorigin
à tag <script>
para resolver as restrições de segurança acima. Agora, o suporte ao Chrome e Firefox para esta propriedade é totalmente gratuito. O Safari tratará crossorigin="anonymous"
como crossorigin="use-credentials"
, e o resultado é que, se o servidor suportar apenas CORS anônimos, o Safari tratará a autenticação como falha. Como o servidor CDN foi projetado para retornar apenas conteúdo estático por motivos de desempenho, é impossível retornar dinamicamente o cabeçalho HTTP necessário para autenticar os CORs com base em solicitações.
O manuseio de exceção do JavaScript parece simples e não é diferente de outros idiomas, mas não é tão fácil capturar todas as exceções e analisar as propriedades. Embora alguns serviços de terceiros agora forneçam serviços do Google Analytics que capturam exceções de JavaScript, se você quiser entender os detalhes e os princípios, deve fazê-lo sozinho.