Como capturar e analisar o erro de JavaScript
Todos os engenheiros do front-end sabem que o JavaScript possui recursos básicos de manuseio de exceções. Podemos lançar um novo erro (), e o navegador também lançará uma exceção quando chamarmos o erro da API. Mas estima-se que a maioria dos engenheiros de front-end não tenha considerado coletar essas informações excepcionais. 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 lançando um novo erro (). 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 do Try-Catch, para o último, devemos ouvir exceções globais e depois pegá-lo.
Try-Catch
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, o Window.localStorage é uma API tal.
A cópia do código é a seguinte:
tentar {
LocalStorage.SetItem ('Date', Date.now ());
} catch (erro) {
repórterror (erro);
}
Outro cenário aplicável de try-capath 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.
A cópia do código é a seguinte:
ouvintes.foreach (function (ouvinte) {
tentar {
ouvinte();
} catch (erro) {
repórterror (erro);
}
});
Window.onerror
Para lugares que o Try-Catch não podem cobrir, se ocorrer uma exceção, ele só poderá ser capturado através do Window.onerror.
A cópia do código é a seguinte:
window.onerror =
função (errorMessage, scripturi, linho) {
repórterror ({
Mensagem: errorMessage,
Script: scripturi,
Linha: Number linear
});
}
Cuidado para não ser inteligente e usar janela.AddeventListener ou window.attachevent para ouvir a janela.onerror. Muitos navegadores implementam apenas o Window.onerror, ou apenas a implementação do Window.onerror é padrão. Considerando que o rascunho padrão também define Window.onerror, precisamos usar o Window.onerror.
Propriedade ausente
Suponha que tenhamos uma função repórterror para coletar exceções capturadas e enviá-las em lotes para o armazenamento do lado do servidor para consulta e análise, que informações queremos coletar? Informações mais úteis incluem: Tipo de erro (nome), mensagem de erro (mensagem), endereço do arquivo de script (script), número da linha (linha), número da coluna (coluna) e rastreamento de pilha. Se uma exceção for capturada através do Try-Catch, todas essas informações estarão no objeto de erro (suportado pelos navegadores mainstream), para que o repórterRor 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 além desses 3 parâmetros serão perdidas.
Mensagens serializadas
Se o objeto de erro for criado por nós mesmos, o erro.Message será controlado por nós. Basicamente, o que colocamos em erro. (O navegador realmente faz um pouco de modificação, como adicionar o 'erro não capturado:' prefixo.) Portanto, podemos serializar os atributos com os quais estamos preocupados (como JSON.Stringify) e armazená -los em erro. eles na janela.onerror apenas retire -o e o desapealizam. Obviamente, isso é limitado ao objeto de erro que criamos nós mesmos.
O quinto parâmetro
Os fabricantes de navegadores também sabem as restrições às quais as pessoas estão sujeitas ao usar o 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 de erro no quinto parâmetro. Como resultado, como o Chrome é mais rápido, uma nova assinatura da Window.onerror foi implementada no Chrome 30, resultando na escrita a seguir do rascunho padrão.
A cópia do código é a seguinte:
window.onerror = função (
errorMessage,
scripturi,
Linho, número,
columnNumber,
erro
) {
if (erro) {
repórterror (erro);
} outro {
repórterror ({
Mensagem: errorMessage,
Script: scripturi,
linha: linenumber,
Coluna: columnNumber
});
}
}
Regularidade de atributos
Os nomes das propriedades do objeto de erro que discutimos antes são baseadas nos métodos de nomeação do Chrome. Portanto, também precisamos de uma função especial para normalizar o objeto de erro, 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 ninguém manter uma tabela de mapeamento.
Semelhante é o formato de rastreamento da pilha. Essa propriedade salva as informações da pilha de uma exceção quando ocorre na forma de texto simples. Nome (identificador), arquivo (script), linha (linha) e coluna (coluna).
Limitações de segurança
Se você também encontrou um erro com a mensagem 'Erro de script', você entenderá do que estou falando, que na verdade são as limitações do navegador para arquivos de script de diferentes fontes. 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 no script. atributo 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 'erro de script.' E todos os outros atributos desaparecem.
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 coletamos do Chrome e do Firefox para serem inúteis 'Erro de script.'.
Cors
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 o XMLHTTPREQUEST para baixar o conteúdo de volta através do CORS e, em seguida, crie uma tag <cript> 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:
A cópia do código é a seguinte:
<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 o XMLHTTPREQUEST, precisamos garantir a ordem correta sozinha. 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>:
A cópia do código é a seguinte:
<Cript>
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 ScheduleReMoteScript e ScheduleInLinEscript e garantir que elas sejam definidas antes da primeira tag <Cript> 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 Etapa2 que foi executada imediatamente foi colocada em uma função de código maior. A função Código 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 SchedelInLinescript possa ser executado um por um na ordem correta. Não vou dar o código detalhado aqui.
Verificação do número da linha
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 erro.Line. Agora, como são todos os códigos incorporados na página, as tags múltiplas <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 fazer o código na primeira tag <cript>, pegue a linha 11000 e a segunda tag <script> o código no código ocupe linha 10012000 (1000 linhas vazias foram inseridas antes da inserção), o código da terceira tag <cript> ocupa a linha 20013000 (2000 linhas vazias foram inseridas antes da inserção) e assim por diante. Em seguida, usamos o atributo de dados* para registrar essas informações para facilitar a verificação de volta.
A cópia do código é a seguinte:
<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 erro de erro.Line for 3005, isso significa que o erro real.script deve ser 'http://cdn.com/step3.js', enquanto o erro real.line deve ser 5. Podemos concluir esse número de linha reversa na função repórterror mencionada anteriormente.
Obviamente, como não podemos garantir que cada arquivo de script tenha 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 um intervalo de 1000 para cada tag <cript>. 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.
atributo crossorigin
As restrições de segurança impostas pelos navegadores do conteúdo de diferentes fontes não estão limitadas a tags <Script>. Como o 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 <MIG>. Se uma tag <mg> for uma fonte diferente, uma vez usada no desenho <lievas>, 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 <MG> resolveu esse problema introduzindo o atributo Crossorigin. Se Crossorigin = "Anonymous", é equivalente aos cors anônimos;
Como a tag <mg> pode fazer isso, por que a tag <cript> não pode fazer isso? Assim, 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á o Crossorigin = "Anonymous" como Crossorigin = "Uso-Credenciais", 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.
Resumir
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.