En el desarrollo front-end, qué factores pueden causar bloqueos de página

El desarrollo front-end no es como el back-end, hay pocos escenarios con una gran cantidad de algoritmos, pero el rendimiento del front-end también debe optimizarse. Un buen código es la base para garantizar el funcionamiento estable y de alto rendimiento de las páginas web. Combinado con los escenarios encontrados en desarrollos anteriores, este artículo clasifica y analiza las razones por las que la página web se congela y brinda las soluciones correspondientes.

Hay muchas razones por las que la página de inicio se congela, que se pueden dividir en dos categorías desde el mecanismo de representación y la operación, a saber:

  • La representación no es oportuna y la página pierde marcos

  • El uso de memoria de la página web es demasiado alto y la operación se congela

Los dos tipos se pueden subdividir de la siguiente manera:

La representación no es oportuna y la página pierde marcos

Ocupando el subproceso js durante mucho tiempo, reflujo de página y redibujado, muchos bloques de carga de recursos

Bloqueo de página causado por exceso de memoria

Las fugas de memoria conducen a un exceso de memoria

  • Fuga de memoria causada por una variable global inesperada

  • Fugas de memoria causadas por cierres

  • temporizador olvidado

  • referencia circular

  • No hay evento de desvinculación cuando se elimina DOM

  • Referencias a elementos DOM que no están desinfectados

Los nodos o eventos DOM ocupan demasiada memoria

1. Representación

1. Ocupar el hilo js durante mucho tiempo

El navegador incluye un subproceso js y un subproceso GUI, y los dos son mutuamente excluyentes.Cuando el subproceso js está ocupado durante mucho tiempo, la representación no será oportuna y la página se congelará.

Ejemplo 1:

document.body.html('为什么不先渲染我');

//程序
$.ajax({
   url: '',
   async: false
})


//运行结果会在ajax执行完毕后,再去渲染页面

La obtención de datos de manera síncrona hará que el subproceso de interfaz gráfica de usuario se cuelgue y la representación se realizará después de que se devuelvan los datos.

Ejemplo 2:

function a (){
    // arr的长度过长时会导致页面卡顿
    arr.forEach(item => {
        ...
    })
}

let inputDom = document.getElementById('input')
let arr = document.getElementsByClassName('.tag')
input.onchange = a

El tiempo de cálculo es demasiado largo y la representación de la página no es oportuna

Razones para el renderizado retrasado:

La frecuencia de renderizado del navegador es generalmente de 60 HZ, es decir, el tiempo requerido para un cuadro es 1 s / 60 = 16,67 ms. Cuando el navegador muestra la página, necesita procesar la lógica js y renderizar, y cada segmento de ejecución no puede exceder los 16,67 EM. De hecho, el funcionamiento del propio sistema de soporte del núcleo del navegador también lleva algo de tiempo, por lo que el tiempo que nos queda es de solo unos 10 ms.

Métodos de optimización comunes:

  • Uso de requestIdleCallback y requestAnimationFrame, fragmentación de tareas

ejemplo

function Task(){
    this.tasks = [];
}
//添加一个任务
Task.prototype.addTask = function(task){
    this.tasks.push(task);
};
//每次重绘前取一个task执行
Task.prototype.draw = function(){
    var that = this;
    window.requestAnimationFrame(function(){
        var tasks = that.tasks;        if(tasks.length){
            var task = tasks.shift();
            task();
        }
        window.requestAnimationFrame(function(){that.draw.call(that)});
    });
};

2. Hay muchos reflujos y redibujados de página

  • Minimizar el diseño

Al obtener atributos de dimensión como scrollTop y clentWidth, el diseño se activará para obtener valores en tiempo real, por lo que estos valores deben almacenarse en caché en el bucle for

Ejemplo:

antes de la optimización

for(var i = 0; i < childs.length; i++){
   childs.style.width = node.offsetWidth + "px";
}

después de la optimización

var width = node.offsetWidth;for(var i = 0; i < childs.length; i++){
   childs.style.width = width + "px";
}
  • Simplificar la estructura DOM

Cuando la estructura DOM es más compleja, es necesario volver a dibujar más elementos. Por lo tanto, el dom debe mantenerse simple, especialmente aquellos que van a ser animados, o escuchar eventos de desplazamiento / movimiento del mouse. Además, usar flex tendrá ventajas en el redibujado que usar float.

3. Bloqueo de carga de recursos

  • js recursos se colocan antes del cuerpo

  • Bloqueo de secuencias de comandos en línea

  • La carga de CSS bloqueará la representación del árbol DOM (css no bloqueará el análisis del árbol DOM)

  • Demasiado bloqueo de recursos

2. Congelamiento de página causado por exceso de memoria

1. Las fugas de memoria conducen a un exceso de memoria

Los navegadores tienen su propio conjunto de mecanismos de recolección de basura. El principal mecanismo de recolección de basura es la eliminación de marcas. Sin embargo, acceder al DOM nativo en IE utilizará un mecanismo de conteo de referencias. Si la memoria inactiva no se recupera a tiempo, se producirán fugas de memoria.

Presente brevemente los dos mecanismos de recolección de basura (GC Garbage Collection)

Marcar claro:

Definición y uso:

Cuando una variable entre en el entorno, márquela como "entrando en el entorno", y cuando la variable salga del entorno, márquela como: "salir del entorno". En cierto punto, el recolector de basura filtrará las variables del entorno y las variables referenciadas por las variables del entorno, y el resto son variables que se consideran listas para reciclarse.

Hasta ahora, las implementaciones js de IE, Firefox, Opera, Chrome y Safari utilizan una estrategia de recolección de basura de marcar y barrer o estrategias similares, pero los intervalos de recolección de basura son diferentes entre sí.

proceso:

  • Cuando el navegador se esté ejecutando, marcará todas las variables almacenadas en la memoria

  • Eliminar las variables en el entorno y las variables a las que se hace referencia en el entorno.

  • Si todavía hay variables marcadas, se considerará como una variable a eliminar

  • El mecanismo de recolección de basura completa el trabajo de limpieza de la memoria, destruye las variables marcadas y recupera el espacio de memoria que ocupan.

recuento de referencia

Definición y uso : el recuento de referencias es el seguimiento del número de veces que se hace referencia a cada valor.

Principio básico: Es el número de referencias a una variable, y cuando se referencia una vez se le suma 1. Cuando el conteo de referencias es 0, se considera lista para ser reciclada

Objeto.

proceso

  • Se declara una variable y se asigna un valor de un tipo de referencia a la variable. El número de referencias a este valor de tipo de referencia es 1

  • Se asigna el mismo valor a otra variable, y el número de referencias de valor de este tipo de referencia se incrementa en 1

  • Cuando a la variable que contiene el valor de este tipo de referencia se le asigna otro valor, el recuento de referencia del valor de este tipo de referencia se reduce en 1

  • Cuando el número de referencias se convierte en 0, significa que el valor debe ser desreferenciado

  • Cuando el mecanismo de recolección de basura se ejecute la próxima vez, liberará la memoria ocupada por el valor con un recuento de referencia de 0

Causas comunes de pérdidas de memoria:

  • Fuga de memoria causada por una variable global inesperada

Solución: Evite usar el modo estricto.

ejemplo

<button onclick="createNode()">添加节点</button>
<button onclick="removeNode()">删除节点</button>
<div id="wrapper"></div>
<script>
  var text = [];
  function createNode() { 
      text.push(new Array(1000000).join('x'));  
      var textNode = document.createTextNode("新节点"),
          div = document.createElement('div');
      div.appendChild(textNode);
      document.getElementById("wrapper").appendChild(div);  
  }
  
  function removeNode() {
      var wrapper = document.getElementById("wrapper"),
          len = wrapper.childNodes.length;
      if (len > 0) {
          wrapper.removeChild(wrapper.childNodes[len - 1]);  
      }
  }
  </script>

Se hace referencia a la variable de texto en createNode, por lo que el texto no se puede reciclar

  • Fugas de memoria causadas por cierres

Ejemplo:

<button onclick="replaceThing()">第二次点我就有泄漏</button>
  <script>
  var theThing = null;
  var replaceThing = function () {
      var originalThing = theThing;
      var unused = function () {
          if (originalThing) {
              console.log("hi");
          };
      }
      theThing = {
          longStr: new Array(1000000).join('*'),
          someMethod: function someMethod() {
              console.log('someMessage');
          }
      };
  };

La razón por la que se filtra el código anterior es que hay dos cierres: unused y someMethod , los cuales comparten el ámbito principal.

Debido a que theThing es una variable global y someMethod es una propiedad de la variable global, el ámbito de cierre al que hace referencia (compartido por unused y somMethod) no se liberará. Dado que originalThing está en el ámbito compartido, originalThing no se liberará. Con replaceThing Continuously llamando, originalThing apunta al anterior theThing, y el nuevo theThing.someMethod se referirá a originalThing, formando así una cadena de referencia de cierre, y longStr es una cadena grande que no se puede liberar, lo que resulta en una pérdida de memoria.

Solución: agregue originalThing = null al final de replaceThing

  • temporizador olvidado

ejemplo

var someResource = getData(); 
setInterval(function() { 
    var node = document.getElementById('Node'); 
    if(node) { 
        // 处理 node 和 someResource 
        node.innerHTML = JSON.stringify(someResource)); 
    } 
}, 1000);

La función de devolución de llamada del temporizador no se recicla (el temporizador se reciclará cuando se detenga)

  • referencia circular

Una referencia circular es cuando el objeto A contiene otro puntero al objeto B, que también contiene una referencia a A.

Porque la implementación de BOM y DOM en IE usa COM, y el mecanismo de recolección de basura que usan los objetos COM es una estrategia de conteo de referencia. Entonces habrá un problema de referencia circular.

Solución: desconecte manualmente el enlace entre el objeto js y el DOM. El valor asignado es nulo.

Ejemplo:

function handle () {
    var element = document.getElementById(“testId”);
    element.onclick = function (){
        alert(element.id)
    }
}

Se hace referencia a las propiedades del elemento en el evento vinculado por el elemento

El evento onclick es un cierre, que puede mantener variables locales en la función para que no se puedan liberar. Es decir, la variable del elemento no se puede liberar y el elemento no se liberará cada vez que se llame y, finalmente, la memoria se pierde.

Solución:

function handle () {
    var element = document.getElementById(“testId”);
    element.onclick = function (){
        alert(element.id)
    }
    element = null
}
  • No hay evento de desvinculación cuando se elimina DOM

Por ejemplo, elimine un botón, pero el evento en el botón no se libera

  • Referencias a elementos DOM que no están desinfectados

2. Los nodos o eventos Dom ocupan demasiada memoria

Para un análisis detallado, vea mi otro artículo ¿Por qué demasiados elementos DOM en una página web hacen que la página se congele?

Ejemplo:

function addDom(){
        let d = document.createDocumentFragment();
       
        for(var i = 0;i<30;i++){
            let li = document.createElement('li')
            li.addEventListener('click', function(e) {
                let _this = e.target;
                let dom = e.target.tagName.toLowerCase();
                _this.style.color = 'red';
            })
        li.innerHTML = `</div>
            <h4>
                测试图片 
            </h4>
            <img style = "height:20px;width:100px" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1591105123139&di=90a63b4962d0b4405ce65c2096a676c2&imgtype=0&src=http%3A%2F%2Fimg0.imgtn.bdimg.com%2Fit%2Fu%3D3769023270%2C3433174748%26fm%3D214%26gp%3D0.jpg"/>
            </div>`
            d.appendChild(li)
        }
        document.getElementById('app').appendChild(d)
    }

El código anterior es una carga desplegable, y el dom se agregará cada vez, lo que eventualmente conducirá a un exceso de memoria.

La solución: usar listas virtuales y delegación de eventos

Resumen: Hay muchos escenarios para bloqueos de página en el proceso de desarrollo real. Puede usar la herramienta de detección de fugas de memoria (sIEve, para IE) para detectar, o puede usar la línea de tiempo, los perfiles o el rendimiento proporcionado por Chrome, que no lo hará. ser descrito en detalle aquí.

Referencia: https://www.cnblogs.com/yanglongbo/articles/9762359.html

https://blog.csdn.net/c11073138/article/details/84728132

Supongo que te gusta

Origin blog.csdn.net/qdmoment/article/details/106590185
Recomendado
Clasificación