Todos os engenheiros do front-end sabem que o JavaScript possui recursos básicos de manuseio de exceção. 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 do front-end nunca tenha pensado em coletar essas informações de exceção
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 de página única é extremamente complexa após a execução por um período de tempo. Os usuários podem ter executado várias operações de entrada antes de chegarem aqui. Como eles podem atualizar se dizem que querem? 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çamos um novo erro (). Se queremos capturar, certamente podemos capturá -lo porque sabemos muito bem onde o arremesso é escrito. No entanto, exceções que ocorrem ao chamar a API do navegador não são necessariamente tão fáceis de capturar. Algumas APIs dizem que as exceções serão lançadas no padrão, e algumas APIs só têm navegadores individuais, lançar exceções devido a diferenças ou defeitos de implementação. 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, Window.LocalStorage é uma API. Uma exceção será lançada após a redação dos dados exceder o limite de capacidade, e isso também será verdade no modo de navegação privado do Safari.
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 inesperadas 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 fará modificações ligeiramente, 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.Message e depois lê -los em window.onerrror para merecê -los. 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. Qualquer atributo que você deseja ler, incluindo atributos personalizados. 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. No entanto, diferentes navegadores nomeiam as propriedades do objeto de erro de maneira diferente. Por exemplo, o endereço do arquivo de script é chamado de script no Chrome, mas o nome do arquivo no Firefox. 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. Esta propriedade salva as informações da pilha de uma exceção quando ocorre em texto simples. Como os formatos de texto usados por cada navegador são diferentes, também é necessário manter uma expressão regular para extrair o nome da função (identificador), arquivo (script), número da linha (linha) e número da coluna (coluna) de cada quadro do texto simples.
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.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 da mesma origem. Mas a colocação de arquivos de script em servidores que não são acelerados pela CDN para desacelerar 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. A etapa2 pode ser executada quando a etapa1 for baixada em um formulário não bloqueador, portanto, também devemos interferir no passo 2 e deixar que ele aguarde a etapa 1 para concluir antes de executar.
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. Se você estiver interessado, pode implementá -lo sozinho.
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 todos os códigos incorporados na página são todos os códigos, várias tags <Script> não podem ser distinguidas pelo erro.script. No entanto, o número da linha dentro de cada tag <Script> é calculado a partir de 1, o que resulta em que não possamos usar informações de exceção para localizar o local do código -fonte em que o erro está localizado.
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, então posso deixar o código na primeira tag <cript> Occupy Line 11000, o código no segundo <Script> Occupy Line 10012000 (1000 linhas vazias foi inserido antes), o código na terceira tag <script> tata 20013000 (2000. 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', e a linha real.
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; Se Crossorigin = "Uso-Credenciais", é equivalente a um CORS certificado.
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 razões de desempenho, é impossível retornar dinamicamente o cabeçalho HTTP necessário para autenticar os CORs com base em solicitações. O Safari é equivalente a não poder usar esse recurso para resolver o problema acima.
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. Agora, embora alguns serviços de terceiros forneçam serviços semelhantes ao Google Analytics que capturam exceções de JavaScript, se você quiser entender os detalhes e os princípios, ainda precisa fazer isso sozinho.