2011-05-17 27 views
39

Si tengo un elemento principal con elementos secundarios que tienen detectores de eventos vinculados a ellos, ¿necesito eliminar esos detectores de eventos antes de borrar el elemento primario? (es decir, parent.innerHTML = '';) ¿Podría haber pérdidas de memoria si los detectores de eventos no están separados de un elemento si se eliminan del DOM?¿Debo eliminar los detectores de eventos antes de eliminar los elementos?

Respuesta

24

Respuesta corta:

Respuesta larga: La mayoría de los navegadores manejan esto correctamente y eliminar esos manipuladores de sí mismos. Hay algunos navegadores más antiguos (IE 6 y 7, si no recuerdo mal) que están estropeando esto. Sí, podría haber pérdidas de memoria. No deberías tener que preocuparte por esto, pero debes hacerlo. Eche un vistazo al this document.

+0

De hecho: aunque la mayoría de los navegadores actuales no sufrirán tanto, IE 7 todavía se usa comúnmente. También eche un vistazo a [Patrones de fuga de memoria en JavaScript] (http://www.ibm.com/developerworks/web/library/wa-memleak/). –

+6

¿Hay alguien lo suficientemente experto como para actualizar esto para el mercado actual de los navegadores? ¿O vale la pena una pregunta por separado? IE7, pensé, fue [prácticamente eliminado] (http://theie7countdown.com/), mientras que [ie8] (http://theie8countdown.com/) sigue dando vueltas. ¿IE8 maneja los oyentes de eventos abandonados? –

+3

6 años después, creo que 'IE <10' se puede considerar obsoleto y no utilizado por nadie que vaya a sitios que no sean Yahoo y AOL en este momento.Cualquiera que use IE de forma no-lógica en este punto probablemente sea más propenso a ser víctima de una estafa telefónica de un indio o de tener un virus que tener problemas con los manejadores de eventos que desaceleren su cangrejo de navegador. –

21

Solo para actualizar la información aquí. He estado probando varios navegadores, específicamente para fugas de memoria para receptores de eventos dependientes circularmente en eventos de carga iframe.

El código utilizado (jsFiddle interfiere con las pruebas de memoria, a fin de utilizar su propio servidor para probar esto):

<div> 
    <label> 
     <input id="eventListenerCheckbox" type="checkbox" /> Clear event listener when removing iframe 
    </label> 
    <div> 
     <button id="startTestButton">Start Test</button> 
    </div> 
</div> 

<div> 
    <pre id="console"></pre> 
</div> 

<script> 

    (function() { 
     var consoleElement = document.getElementById('console'); 
     window.log = function(text) { 
      consoleElement.innerHTML = consoleElement.innerHTML + '<br>' + text; 
     }; 
    }()); 

    (function() { 
     function attachEvent(element, eventName, callback) { 
      if (element.attachEvent) 
      { 
       element.attachEvent(eventName, callback); 
      } 
      else 
      { 
       element[eventName] = callback; 
      } 
     } 

     function detachEvent(element, eventName, callback) { 
      if (element.detachEvent) 
      { 
       element.detachEvent(eventName, callback); 
      } 
      else 
      { 
       element[eventName] = null; 
      } 
     } 

     var eventListenerCheckbox = document.getElementById('eventListenerCheckbox'); 
     var startTestButton = document.getElementById('startTestButton'); 
     var iframe; 
     var generatedOnLoadEvent; 

     function createOnLoadFunction(iframe) { 
      var obj = { 
       increment: 0, 
       hugeMemory: new Array(100000).join('0') + (new Date().getTime()), 
       circularReference: iframe 
      }; 

      return function() { 
       // window.log('iframe onload called'); 
       obj.increment += 1; 
       destroy(); 
      }; 
     } 

     function create() { 
      // window.log('create called'); 
      iframe = document.createElement('iframe'); 

      generatedOnLoadEvent = createOnLoadFunction(iframe); 
      attachEvent(iframe, 'onload', generatedOnLoadEvent); 

      document.body.appendChild(iframe); 
     } 

     function destroy() { 
      // window.log('destroy called'); 
      if (eventListenerCheckbox.checked) 
      { 
       detachEvent(iframe, 'onload', generatedOnLoadEvent) 
      } 

      document.body.removeChild(iframe); 
      iframe = null; 
      generatedOnLoadEvent = null; 
     } 

     function startTest() { 
      var interval = setInterval(function() { 
       create(); 
      }, 100); 

      setTimeout(function() { 
       clearInterval(interval); 
       window.log('test complete'); 
      }, 10000); 
     } 

     attachEvent(startTestButton, 'onclick', startTest); 
    }()); 

</script> 

Si no hay pérdida de memoria, la memoria utilizada se incrementará en torno a 1000kb o menos después de la las pruebas se ejecutan. Sin embargo, si hay una pérdida de memoria, la memoria aumentará en aproximadamente 16,000kb. La eliminación del detector de eventos primero siempre da como resultado un menor uso de memoria (sin pérdidas).

Resultados:

  • IE6 - Pérdida de memoria
  • IE7 - Pérdida de memoria
  • IE8 - fugas sin memoria
  • IE9 - pérdida de memoria (???)
  • IE10 - pérdida de memoria (???)
  • IE11 - sin pérdida de memoria
  • Edge (20) - sin pérdida de memoria
  • Chrome (50) - sin pérdida de memoria
  • Firefox (46) - difícil de decir, no gotea mal, entonces ¿tal vez solo un recolector de basura ineficaz? Termina con 4MB extra sin razón aparente.
  • Opera (36) - no hay pérdida de memoria
  • Safari (9) - fugas sin memoria

Conclusión: Sangrado aplicaciones de extremo probablemente puede salirse con la no eliminación de los detectores de eventos. Pero aún así lo consideraría una buena práctica, a pesar de la molestia.

Cuestiones relacionadas