Validação de Nós Críticos no DOM
A detecção de tela branca baseada no DOM fundamenta-se na verificação da presença e renderização de elementos estruturais essenciais, como o contêiner raiz da aplicação ou cabeçalhos principais. O objetivo é assegurar que a árvore DOM não apenas exista, mas que possua dimensões visíveis e conteúdo real.
Critérios de Avaliação
- Existência do Nó: Confirmação via
document.querySelectorde que o seletor alvo foi montado. - Densidade de Conteúdo: Validação de que
innerTextpossui caracteres válidos ou que há elementos filhos renderizados. - Visibilidade Computada: Verificação de que o elemento não está oculto por
display: none,visibility: hiddenou opacidade zero, e que suas dimensões físicas (getBoundingClientRect) são maiores que zero.
function monitorarConteinerRaiz(seletorAlvo, configuracoes = {}) {
const {
tempoMaximo = 6000,
frequenciaVerificacao = 300,
aoDetectarTelaBranca = () => {}
} = configuracoes;
const tempoInicial = performance.now();
const intervalo = setInterval(() => {
const tempoDecorrido = performance.now() - tempoInicial;
if (tempoDecorrido >= tempoMaximo) {
clearInterval(intervalo);
aoDetectarTelaBranca({
motivo: 'timeout_renderizacao',
seletor: seletorAlvo,
duracao: tempoDecorrido
});
return;
}
const no = document.querySelector(seletorAlvo);
if (!no) return;
const possuiTexto = no.innerText.trim().length > 0;
const possuiFilhos = no.children.length > 0;
if (!possuiTexto && !possuiFilhos) return;
const estilos = window.getComputedStyle(no);
const dimensoes = no.getBoundingClientRect();
const estaVisivel =
dimensoes.height > 0 &&
dimensoes.width > 0 &&
estilos.visibility !== 'hidden' &&
parseFloat(estilos.opacity) > 0;
if (estaVisivel) {
clearInterval(intervalo);
}
}, frequenciaVerificacao);
}
Captura de Exceções e Falhas de Recursos
Erros de execução e falhas no carregamento de ativos críticos são causas primárias de telas brancas. A interceptação global permite categorizar e reportar essas falhas antes que a aplicação colapse silenciosamente.
Erros de Runtime e Promessas
Erros síncronos são interceptados via window.onerror ou ouvintes de evento error, enquanto rejeições de promessas não tratadas exigem o evento unhandledrejection.
window.addEventListener('error', (evento) => {
const alvo = evento.target;
// Interceptação de falhas em ativos (Scripts, CSS, Imagens)
if (alvo && (alvo instanceof HTMLScriptElement || alvo instanceof HTMLLinkElement)) {
emitirAlerta({
categoria: 'falha_carregamento_ativo',
url: alvo.src || alvo.href,
tag: alvo.tagName
});
return;
}
// Interceptação de erros de execução JS
const erro = evento.error;
if (erro && evento.filename.includes('bundle')) {
emitirAlerta({
categoria: 'excecao_runtime',
mensagem: erro.message,
rastreamento: erro.stack
});
}
}, true);
window.addEventListener('unhandledrejection', (evento) => {
emitirAlerta({
categoria: 'promessa_nao_tratada',
mensagem: evento.reason?.message || 'Rejeição desconhecida',
rastreamento: evento.reason?.stack
});
});
Análise de Métricas de Performance Web
A API de Performance do navegador expõe marcos temporais cruciais. O atraso ou ausência de eventos como First Contentful Paint (FCP) e Largest Contentful Paint (LCP) são fortes indicadores de bloqueios de renderização.
const rastrearMetricasDePintura = () => {
const observador = new PerformanceObserver((lista) => {
for (const entrada of lista.getEntries()) {
if (entrada.name === 'first-contentful-paint' && entrada.startTime > 5000) {
registrarMetrica({
tipo: 'FCP',
valor: entrada.startTime,
status: 'degradado'
});
}
if (entrada.entryType === 'largest-contentful-paint' && entrada.startTime > 10000) {
registrarMetrica({
tipo: 'LCP',
valor: entrada.startTime,
elemento: entrada.element?.tagName
});
}
}
});
observador.observe({ entryTypes: ['paint', 'largest-contentful-paint'] });
};
rastrearMetricasDePintura();
Integração com Ciclos de Vida de Frameworks
Em Single Page Applicatoins (SPAs), exceptions não capturadas dentro da árvore de componentes podem desmontar a interface inteira. Frameworks como React oferecem mecanismos de fronteira de erro para isolar essas falhas.
class FronteiraDeErroUI extends React.Component {
state = { falhou: false, detalhes: null };
static getDerivedStateFromError(erro) {
return { falhou: true };
}
componentDidCatch(erro, informacoes) {
transmitirErro({
origem: 'react_error_boundary',
mensagem: erro.toString(),
arvoreComponentes: informacoes.componentStack
});
}
render() {
if (this.state.falhou) {
return (
<div className="ui-degradada">
<h3>Ocorreu um erro na renderização.</h3>
<button onClick={() => window.location.reload()}>Recarregar Página</button>
</div>
);
}
return this.props.children;
}
}
Verificação Visual e Densidade de Pixels
Cenários onde o DOM está intacto e não há erros no console, mas a tela permanece visualmente vazia (devido a conflitos de CSS ou sobreposição de elementos), exigem análise em nível de pixel. Uma abordagem otimizada utiliza tipagem de arrays para processar dados de imagem de forma performática.
async function avaliarDensidadeVisual(seletor) {
const alvo = document.querySelector(seletor);
if (!alvo) return;
const canvas = document.createElement('canvas');
canvas.width = alvo.scrollWidth;
canvas.height = alvo.scrollHeight;
const contexto = canvas.getContext('2d');
// Em produção, utiliza-se uma biblioteca como html2canvas para renderizar o DOM no canvas
// await html2canvas(alvo, { canvas, useCORS: true, logging: false });
const dadosImagem = contexto.getImageData(0, 0, canvas.width, canvas.height);
// Otimização: usar Uint32Array para leitura de pixels em 32 bits
const pixels32 = new Uint32Array(dadosImagem.data.buffer);
let pixelsVazios = 0;
const totalPixels = pixels32.length;
// Verificação de cor branca (formato RGBA little-endian: 0xFFFFFFFF)
const corBranca = 0xFFFFFFFF;
for (let i = 0; i < totalPixels; i++) {
if (pixels32[i] === corBranca) {
pixelsVazios++;
}
}
const taxaVazio = pixelsVazios / totalPixels;
if (taxaVazio > 0.92) {
notificarErroVisual({
tipo: 'tela_branca_pixel',
taxa: taxaVazio.toFixed(2)
});
}
}