Em relação à descrição dos indicadores de desempenho do front-end, a indústria tem suas próprias opiniões. Em resumo, está relacionado ao desempenho da primeira tela e à fluência da página. a perspectiva da análise da fluência da página. [Recomendação de tutorial relacionado: "Tutorial Angular"]
O que é fluência de página?
A fluência da página é determinada pela taxa de quadros FPS (Frames Per Second - quadros transmitidos por segundo). Geralmente, a taxa de atualização da tela dos navegadores convencionais é de 60 Hz (atualizada 60 vezes por segundo), e a taxa de quadros ideal é de 60 FPS. Quanto maior a taxa de quadros, mais suave será a página. 60 Hz significa que a tela será atualizada a cada 16,6 ms, o que significa que cada renderização de página precisa ser concluída em 16,6 ms, caso contrário a página perderá quadros e congelará.根因在于:浏览器中的JavaScript 执行和页面渲染会相互阻塞
.
Nos devtools do Chrome, podemos executar Cmd+Shift+P e inserir show fps para abrir rapidamente o painel fps, conforme mostrado na figura a seguir:
Observando o painel FPS, podemos monitorar facilmente a fluência da página atual.
1 Fatores que afetam o desempenho da página
Se a interação da página é suave depende se a resposta da página é suave, e a resposta da página é essencialmente o processo de renderizar novamente as alterações no status da página para a página.
O processo de resposta da página é aproximadamente o seguinte:
Geralmente, a lógica de processamento de eventos do manipulador de eventos não consome muito tempo, portanto, os fatores que afetam o desempenho do Angular residem principalmente no异步事件触发
e变更检测
. Geralmente, a lógica de processamento de eventos do manipulador de eventos não consome muito tempo, portanto, os fatores que afetam o desempenho do Angular residem principalmente no acionamento assíncrono de eventos e na detecção de alterações.
Para o Angular, o processo de renderização da página é o processo de detecção de alterações. Pode-se entender que a detecção de alterações do Angular deve ser concluída em 16,6 ms para evitar perda e atraso do quadro da página.
O desempenho da resposta da página pode ser otimizado a partir dos três aspectos a seguir.
(1) Para o estágio de evento de acionamento, o acionamento de eventos assíncronos pode ser reduzido para reduzir o número total de detecções de alterações e re-renderização
(2) Para o estágio de lógica de execução do manipulador de eventos, o tempo de execução pode ser reduzido por meio da otimização complexa; lógica de código;
(3) Para a ligação de dados de detecção de alterações e fase de atualização do DOM, o número de cálculos de detecção de alterações e dados de modelo pode ser reduzido para reduzir o tempo de renderização
para (2) manipulador de eventos, problemas específicos precisam ser analisados; detalhes e não serão discutidos. Foco principalmente em (1) (3) ) Otimização
2 Plano de Otimização
2.1 Reduzir o acionamento de eventos assíncronos
Angular No modo de detecção de alterações padrão, os eventos assíncronos acionarão a detecção de alterações globais. melhorará muito o desempenho do Angular.
Os eventos assíncronos incluem eventos de tarefas macro e eventos de micro tarefas
A otimização de eventos assíncronos é principalmente para eventos de escuta de documentos. Por exemplo, ouça click, mouseup, mousemove... e outros eventos no documento.
Cenário de evento de escuta:
Renderer2.listen(document,…)
fromEvent(document,…)
document.addEventListener(…)
O evento de escuta DOM deve ser removido quando não for necessário ser acionado.
Por exemplo: [pop]
cenários de uso do comando prompt box: filtrar colunas da tabela, clicar em algum lugar diferente do ícone ou rolar a página, ocultando a caixa pop-up do filtro de coluna
O método anterior era monitorar diretamente o evento de clique e o evento de rolagem. do documento no comando pop Desta forma: A única desvantagem é que a caixa de prompt não é exibida, mas ainda há eventos de monitoramento, o que é muito irracional.
Solução razoável: ouça apenas os eventos de clique e rolagem quando a caixa de prompt for exibida e remova os eventos de escuta quando ela estiver oculta.
Para eventos de escuta DOM acionados com frequência, você pode usar operadores rjx para otimizar eventos. Consulte Operadores Rjx para obter detalhes. Mármores RxJS.
2.2 Detecção de Mudanças
O que é detecção de mudanças?
Para entender a detecção de alterações, podemos procurar respostas nos objetivos da detecção de alterações. O objetivo da detecção de alterações angulares é manter o modelo (código TypeScript) e o modelo (HTML) sincronizados. Portanto, detecção de alterações pode ser entendida como: detectar alterações no modelo e atualizar o modelo ( DOM ) ao mesmo tempo .
Qual é o processo de detecção de alterações?
Ao realizar a detecção de alterações em uma ordem de cima para baixo na árvore de componentes, ou seja, a detecção de alterações é executada primeiro no componente pai e depois nos componentes filhos. Primeiro, verifique as alterações de dados do componente pai e, em seguida, atualize o modelo do componente pai. Ao atualizar o modelo, ao encontrar o componente filho, ele atualizará o valor vinculado ao componente filho e, em seguida, inserirá o componente filho para ver se o componente filho. O índice do valor de entrada @Input foi alterado. Se for alterado, marque o subcomponente como sujo, o que requer detecção de alterações subsequente. Depois de marcar o subcomponente, continue a atualizar o modelo por trás do subcomponente no componente pai. foram atualizados, faça alterações na detecção do subcomponente.
2.2.1 Princípio da detecção de alterações angulares
No modo padrão de detecção de alterações padrão, o princípio dos eventos assíncronos que acionam a detecção de alterações do Angular é que angular chama o método tick() de ApplicationRef ao processar eventos assíncronos usando Zone.js para executar a partir do componente raiz para o subcomponente Detecção de alterações. Durante o processo de inicialização da aplicação Angular, uma zona (NgZone) é instanciada e então toda a lógica é executada no objeto _inner do objeto.
Zone.js implementa as seguintes classes:
O princípio do processo de detecção é aproximadamente o seguinte:
as operações do usuário acionam eventos assíncronos (por exemplo: eventos DOM, solicitações de interface...)
=> A classe ZoneTask lida com eventos. O método runTask() de zone é chamado na função invocaTask(). No método runTask, zone passa o atributo de instância _zoneDelegate e chama o gancho de ZoneSpec
=> os três ganchos de ZoneSpec (onInvokeTask, onInvoke, onHasTask) passam o checkStable. () função Trigger zone.onMicrotaskEmpty.emit(null) notificação
=> O componente raiz chama tick() depois de ouvir onMicrotaskEmpty e chama detectChanges()
no método tick para iniciar a detecção do componente raiz
=> ··· refreshView()
chama executeTemplate()
, no método executeTemplate
Chame templateFn()
para atualizar o valor vinculado ao modelo e ao subcomponente (这时候会去检测子组件的
输入引用是否改变,如果有改变,会将子组件标记为
Dirty ,也就是该子组件需要变更检测
)
Fluxograma detalhado do princípio de detecção de alterações:
Simplifique o processo:
acione um evento assíncrono
=> ZoneTask manipula o evento
=> ZoneDelegate chama o gancho ZoneSpec para acionar a notificação onMicrotaskEmpty
=> o componente raiz recebe a notificação onMicrotaskEmpty, executa tick() e começa a detectar e atualizar o dom
Como pode ser visto no código acima,当微任务为空的时候才会触发变更检测
.
Fluxograma simples do princípio de detecção de alterações:
Blog de referência Angular de análise de código-fonte Zone.js.
2.2.2 Solução de otimização de detecção de alterações
1) Use
o princípio do modo OnPush: Reduza o tempo gasto na detecção de uma alteração.
A diferença entre o modo OnPush e o modo Padrão é que eventos de escuta do DOM, eventos de timer e promessas não acionarão a detecção de alterações. O status do componente no modo Padrão é sempre CheckAlways, o que significa que o componente deve ser testado a cada ciclo de detecção.
No modo OnPush: As situações a seguir acionarão a detecção de alterações
S1 e a referência @Input do componente a ser alterada.
S2. Eventos vinculados ao DOM do componente, incluindo eventos vinculados ao DOM de seus subcomponentes, como clicar, enviar e passar o mouse. @HostListener()
Nota:
os eventos DOM monitorados por meio de renderer2.listen() não acionarão a detecção de alterações.
O método de escuta nativo de dom.addEventListener() não acionará a detecção de alterações
S3 e os eventos de assinatura observáveis também são definidos. ao mesmo tempo.
S4. Use os seguintes métodos para acionar manualmente a detecção de alterações:
ChangeDetectorRef.detectChanges(): aciona a detecção de alterações para o componente atual e subcomponentes não OnPush.
ChangeDetectorRef.markForCheck(): marca a visualização atual e todos os seus ancestrais como sujos, e a detecção será acionada no próximo ciclo de detecção.
ApplicationRef.tick(): Não acionará a detecção de alterações
2)
Princípio de uso de NgZone.runOutsideAngular(): Reduza o número de detecções de alterações
e grave o monitoramento de eventos dom global no retorno de chamada do método NgZone.runOutsideAngular() O evento dom irá. não aciona a detecção de alterações. Se o componente atual não tiver sido atualizado, você pode executar o gancho detectChanges() de ChangeDetectorRef na função de retorno de chamada para acionar manualmente a detecção de alterações do componente atual.
Exemplo: componente de ícone dinâmico app-icon-react
2.2.3 Método de depuração
1: você pode usar o plug-in Angular DevTools no console do navegador para visualizar um determinado evento DOM e o status de detecção do angular:
Método 2: Você pode inserir diretamente: ng.profiler.timeChangeDetection() no console para visualizar o tempo de detecção. Este método pode visualizar o tempo de detecção global. Blog de referência Criação de perfil de detecção de alterações angulares
2.3 Otimização do modelo (HTML)
2.3.1 Reduza a renderização do DOM: ngFor mais trackBy
Usando o atributo trackBy de *ngFor, o Angular apenas altera e renderiza novamente as entradas alteradas sem ter que recarregar toda a lista de entradas.
Por exemplo: cenário de classificação de tabelas. Se trackBy for adicionado a ngFor, apenas os elementos dom da linha serão movidos quando a tabela for renderizada. Se trackBy não for adicionado, os elementos dom da tabela existente serão excluídos primeiro e, em seguida, os elementos dom da linha serão adicionados. Obviamente o desempenho de mover apenas elementos dom será muito melhor.
2.3.2 Não use funções em expressões de modelo.
Não use chamadas de função em expressões de modelo Angular. Em vez disso, você pode usar uma barra vertical ou uma variável após o cálculo manual. Quando funções são usadas em modelos, independentemente de o valor ter sido alterado ou não, a função será executada sempre que a detecção de alterações for realizada, o que afetará o desempenho.
Cenários para usar funções em modelos:
2.3.3 Reduza o uso de ngFor
O uso de ngFor afetará o desempenho quando a quantidade de dados for grande.
Exemplo:
usando ngFor:
Não usar ngFor: desempenho melhorado cerca de 10 vezes