Em JavaScript, devemos usar variáveis locais em vez de variáveis globais, tanto quanto possível. Todo mundo conhece essa frase, mas quem a disse primeiro? Por que fazer isso? Existe alguma base para isso? Se você não fizer isso, quanta perda isso causará no desempenho? Este artigo explorará as respostas a essas perguntas e compreenderá fundamentalmente quais fatores estão relacionados ao desempenho de leitura e escrita de variáveis.
【Original】Desempenho variável JavaScript
【Autor】Nicholas C. Zakas
[Tradução] Em JavaScript, por que devemos usar variáveis locais sempre que possível?
[Tradutor] Mingda
O seguinte é uma tradução do texto original:
Sobre a questão de como melhorar o desempenho do JavaScript, a sugestão mais ouvida é usar variáveis locais em vez de variáveis globais. Este é um conselho que ficou comigo e nunca o questionei em meus nove anos de trabalho em desenvolvimento web, e é baseado no método de manipulação de escopo e resolução de identificador (resolução de identificador) do JavaScript.
Em primeiro lugar, precisamos deixar claro que as funções são incorporadas como objetos em JavaScript. O processo de criação de uma função é na verdade o processo de criação de um objeto. Cada objeto função possui uma propriedade interna chamada [[Scope]], que contém as informações do escopo quando a função foi criada. Na verdade, o atributo [[Scope]] corresponde a uma lista de objetos (Objetos Variáveis), e os objetos da lista podem ser acessados de dentro da função. Por exemplo, se criarmos uma função global A, então a propriedade interna [[Scope]] de A contém apenas um objeto global (Objeto Global), e se criarmos uma nova função B em A, então o atributo [[Scope] ] de B contém dois objetos, o objeto Objeto de Ativação da função A está na frente e o objeto global (Objeto Global) está atrás.
Quando uma função é executada, um objeto executável (Objeto de Execução) é automaticamente criado e vinculado a uma cadeia de escopo (Cadeia de Escopo). A cadeia de escopo será estabelecida através das duas etapas a seguir para resolução do identificador.
1. Primeiro, copie os objetos nas propriedades internas do objeto de função [[Scope]] para a cadeia de escopo em ordem.
2. Em segundo lugar, quando a função for executada, um novo objeto Objeto de Ativação será criado. Este objeto contém as definições deste, parâmetros (argumentos) e variáveis locais (incluindo parâmetros nomeados). Este objeto Objeto de Ativação será colocado em ação. . A frente da cadeia de domínio.
Durante a execução do código JavaScript, quando um identificador for encontrado, ele será pesquisado na cadeia de escopo do contexto de execução (Contexto de Execução) com base no nome do identificador. A partir do primeiro objeto na cadeia de escopo (o Objeto de Ativação da função), se não for encontrado, procure o próximo objeto na cadeia de escopo e assim por diante, até que a definição do identificador seja encontrada. Se o último objeto do escopo, que é o Objeto Global, não for encontrado após a pesquisa, um erro será gerado, avisando ao usuário que a variável está indefinida. Este é o modelo de execução de função e o processo de resolução de identificador (Resolução de identificador) descrito no padrão ECMA-262. Acontece que a maioria dos mecanismos JavaScript são realmente implementados dessa maneira. Deve-se notar que ECMA-262 não obriga o uso desta estrutura, mas apenas descreve esta parte da função.
Após entender o processo de resolução do identificador (Resolução do Identificador), podemos entender porque as variáveis locais são resolvidas mais rapidamente do que as variáveis em outros escopos, principalmente porque o processo de busca é bastante encurtado. Mas quão mais rápido será? Para responder a essa pergunta, simulei uma série de testes para testar o desempenho de variáveis em diferentes profundidades de escopo.
O primeiro teste é escrever o valor mais simples em uma variável (aqui é usado o valor literal 1). O resultado é mostrado na figura abaixo, o que é muito interessante:
Não é difícil ver pelos resultados que quando o processo de análise do identificador requer pesquisa profunda, haverá perda de desempenho e o grau de perda de desempenho aumentará com o aumento da profundidade do identificador. Não é novidade que o Internet Explorer teve o pior desempenho (mas, para ser justo, houve algumas melhorias no IE 8). É importante notar que existem algumas exceções aqui, o Google Chrome e a última versão meia-noite do WebKit têm um tempo de acesso às variáveis muito estável e não aumentam com o aumento da profundidade do escopo. Claro, isso deve ser atribuído aos motores JavaScript da próxima geração que eles usam, V8 e SquirrelFish. Esses mecanismos realizam otimizações ao executar código, e está claro que essas otimizações tornam o acesso às variáveis mais rápido do que nunca. O Opera também teve um bom desempenho, sendo muito mais rápido que o IE, o Firefox e a versão atual do Safari, mas mais lento que os navegadores baseados em V8 e Squirrelfish. O desempenho do Firefox 3.1 Beta 2 é um pouco inesperado. A eficiência de execução das variáveis locais é muito alta, mas à medida que o número de camadas de escopo aumenta, a eficiência é bastante reduzida. Deve-se observar que estou usando as configurações padrão aqui, o que significa que o Firefox não está com a função Trace ativada.
Os resultados acima foram obtidos realizando operações de gravação em variáveis. Na verdade, eu estava curioso para saber se a situação seria diferente ao ler variáveis, então fiz o seguinte teste. Verificou-se que a velocidade de leitura é ligeiramente mais rápida que a velocidade de escrita, mas a tendência de mudanças no desempenho é consistente.
Como no teste anterior, o Internet Explorer e o Firefox ainda foram os mais lentos, e o Opera mostrou um desempenho muito atraente. Da mesma forma, o Chrome e a versão mais recente do Webkit Midnight Edition mostraram tendências de desempenho que nada têm a ver com a profundidade do escopo. vale a pena prestar atenção. Sim, o tempo de acesso variável no Firefox 3.1 Beta 2 ainda apresenta um estranho salto de profundidade.
Durante o teste, descobri um fenômeno interessante, que é que o Chrome terá perdas adicionais de desempenho ao acessar variáveis globais. O tempo de acesso às variáveis globais não tem nada a ver com o nível de escopo, mas será 50% maior que o tempo de acesso às variáveis locais do mesmo nível.
Que esclarecimentos essas duas provas podem nos trazer? A primeira é verificar o antigo ponto de vista, que é utilizar ao máximo variáveis locais. Em todos os navegadores, acessar variáveis locais é mais rápido do que acessar variáveis entre escopos, incluindo variáveis globais. Os seguintes pontos devem ser a experiência adquirida através deste teste:
* Verifique cuidadosamente todas as variáveis utilizadas na função Se houver uma variável que não esteja definida no escopo atual e seja usada mais de uma vez, então devemos salvar esta variável em um. variável local, use esta variável local para realizar operações de leitura e gravação. Isso pode nos ajudar a reduzir a profundidade de pesquisa de variáveis fora do escopo para 1. Isso é especialmente importante para variáveis globais, porque as variáveis globais são sempre pesquisadas na última posição da cadeia de escopo.
* Evite usar a instrução with. Porque irá modificar a cadeia de escopo do contexto de execução (Contexto de Execução) e adicionar um objeto (Objeto Variável) na frente. Isso significa que durante a execução de with, as variáveis locais reais são movidas para a segunda posição na cadeia de escopo, o que causará perda de desempenho.
* Se você tem certeza de que um trecho de código definitivamente lançará uma exceção, evite usar try-catch, porque a ramificação catch é processada na mesma cadeia de escopo que com. No entanto, não há perda de desempenho no código da ramificação try, portanto ainda é recomendado usar try-catch para detectar erros imprevisíveis.
Se você quiser mais discussão sobre este tópico, dei uma pequena palestra no Mountain View JavaScript Meetup no mês passado. Você pode baixar os slides no SlideShare ou assistir ao vídeo completo da festa, que começa por volta dos 11 minutos da minha palestra.
Notas do Tradutor:
Se você tiver alguma dúvida ao ler este artigo, sugiro que leia os dois artigos a seguir:
* "Modelo de execução de modelo de objeto JavaScript" escrito por Richie
* "ECMA-262 Terceira Edição", consulte principalmente o Capítulo 10, que é o Contexto de Execução. Os termos mencionados neste artigo são explicados em detalhes lá.
No final, Nicholas mencionou um Meetup JavaScript em Mountain View. O site Meetup é na verdade um site de organização para várias atividades do mundo real. Você precisa contornar o firewall para acessá-lo. atividades para participar. hehe.