2010-12-12 11 views
6

Llegué a AS3 del mundo JS, y debo confesar que las funciones anónimas son mi debilidad. Tiendo a usarlos en todas partes. Ahora, viniendo a AS3 escuché y leí en muchos lugares, que AS y Flash son enormemente malos en el manejo de recolección de basura, que uno debe vaciar, eliminar y eliminar todos los manejadores de eventos y objetos manualmente para evitar pérdidas de memoria extrañas e inexplicables y colisiones. No estoy seguro de qué parte de esto es cierto, pero me gustaría seguir las mejores prácticas desde el principio.Funciones anónimas como controladores de eventos en Action Script - ¿está bien o mal?

Así que mi pregunta sería: ¿qué tan malo es la idea de usar funciones anónimas como controladores de eventos? Considere, por ejemplo, un código como este:

addEventListener(Event.ENTER_FRAME, function() : void { 
    controls.elapsed = stream.time; 
}); 

contorls.elapsed es el organismo, que además de ajustar el tiempo de reproducción actual para el reproductor de vídeo, actualiza toda la interfaz de usuario, y corriente es NetStream objeto, que transmite el video real.

Hay muchos otros lugares donde la función anónima puede hacer que el código sea más limpio e intuitivo. Compruebe el siguiente código para el sencillo efecto de aparición gradual de la barra de control:

public function showControls() : void 
    { 
     var self:Controls = this; 

     if (!visible) { 
      visible = true; 
      fadeTimer = new Timer(30, 10); 
      fadeTimer.addEventListener(TimerEvent.TIMER, function() : void { 
       self.alpha += 0.1; 
      }); 
      fadeTimer.addEventListener(TimerEvent.TIMER_COMPLETE, function() : void { 
       self.alpha = 1; 
      }); 
      fadeTimer.start(); 
     } 
    } 

estoy totalmente al igual que cómo se ve y se inscribe en el código, pero estoy preocupado por las fugas. Si bien el controlador Event.ENTER_FRAME probablemente nunca se volvería dañino en esta forma, ¿qué pasa con los escuchas de temporizador? ¿Debo eliminar esos oyentes manualmente, o se eliminarán automáticamente, tan pronto como establezca fadeTimer = null? ¿Es posible eliminar oyentes correctamente con funciones anónimas?

+1

No soy seguidor de las funciones anónimas. Por un lado, son feos, tampoco se puede reutilizar la función en otro lugar (lo que posiblemente conduce a un código duplicado) y, por último, crean un objeto de activación que tiene algunos impactos de rendimiento y memoria. http://onflex.org/ACDS/AS3TuningInsideAVM2JIT.pdf – Allan

+3

¿Hay algo en AS que no cause algún impacto en el rendimiento y la memoria? :) Bueno, en mi comprensión, las funciones anónimas solo son útiles, cuando uno no necesita reutilizar esas funciones, no quiere complicar la definición de clase y quiere mantener toda la lógica en un solo lugar. Así es como y cuando tiendo a usarlos. Gracias por el enlace, lo verificaré. – jayarjo

+2

Hmm ... "algún impacto en el rendimiento y la memoria" que en realidad resultó ser una cita. Ahora, ¿qué tipo de declaración es? ¿Qué significa "algo"? Si esto es leído por su significado, entonces "algunos" suena como un valor insignificante. ¿O no? Qué muy vago. – jayarjo

Respuesta

2

No hay nada de malo con el uso de métodos de función donde funciona. En lo que respecta a las fugas de memoria, debe rastrear el objeto hasta el escenario para ver si se puede eliminar.

Adición de un controlador de ENTER_FRAME evento para el control asegura que el control tiene una referencia a la función anónima. Como el código es parte del control (o eso parece), está bien, ya que la función anónima se eliminará cuando esté el control.

Adición de un controlador de eventos para el temporizador asegura que el temporizadortiene una referencia a la función anónima . Si el temporizador se está ejecutando, mantendrá viva la referencia de función anónima y, por asociación, el control de enture. Sin embargo, una vez que el temporizador se haya detenido, tanto él como la función se deben recopilar.

Si todo lo demás falla, ¡utilice el generador de perfiles y vea! ;)

+0

¿Por "debe recogerse" quiere decir automáticamente? o tendré que interferir con una función de eliminación manual()? :) – jayarjo

+0

Me refiero a que la recolección de basura debería eliminarlo automáticamente cuando realiza un barrido. –

+1

El código anterior, el fadetimer nunca será basura recolectada. Necesita el removeEventListener explícito o configurar addEventListener para usar WeakReferences = false. (es decir, addEventListener (type, callback, false [usecapture], 0 [priority], true [useweakref]); Eliminar el control del escenario NO eliminará el controlador de eventos. – ansiart

3

Lo haría algo así. Y, asegúrese de utilizar dispose() cuando quiera asegurarse de borrar el temporizador si está interrumpiendo.

private function showControls() : void 
{ 
    if(_isVisible) 
     return; 

    // start you control here 
    _fadeTimer = new Timer(30, 10); 
    _fadeTimer.removeEventListener(TimerEvent.TIMER, updateFade); 
    _fadeTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, updateFadeComplete); 
    _fadeTimer.start(); 
} 

private function updateFade(event : TimerEvent) : void 
{ 
    // update fade here 
} 

private function updateFadeComplete(event : TimerEvent) : void 
{ 
    dispose(); 
} 


private function dispose() : void 
{ 
    if(_fadeTimer) 
    { 
     _fadeTimer.stop(); 
     _fadeTimer.removeEventListener(TimerEvent.TIMER, updateFade); 
     _fadeTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, updateFadeComplete); 
     _fadeTimer = null; 
    } 
} 
+0

Por cierto, ¿por qué estos subrayados en todas partes? Agregan un poco a la torpeza del código, ¿no? – jayarjo

+2

Lo siento. Porque son miembros privados de la clase. – Mattias

+3

@jayarjo - Los caracteres de subrayado a son una convención común, pero no obligatoria, para nombrar un campo privado/variable –

7

Acabo de dar cuenta de esta publicación: hay un par de cosas que podrían serle útiles. Uno es arguments.callee (que es una referencia a la función actual en la que se encuentra). Esto es útil para eliminar referencias en funciones anónimas. Además, se puede observar que podría usar referencias débiles en su código addEventListener; sin embargo, esto no funcionará para las variables que son anónimas, ya que obtendrían GC casi de inmediato.Para simplificar, reescribí el código de esta manera: (debería funcionar, no lo he probado)

private function showControls() : void { 

    if (visible) { 
     return; 
    } 

    var self:DisplayObject = this; 

    var fadeTimer= new Timer(30,10); 
    var handler = function(e:Event) { 

     switch (e.type) { 

      // timer complete 
      case TimerEvent.TIMER_COMPLETE: 

       // remove references to this anonymous function -- for garbage collection 
       fadeTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, arguments.callee); 
       fadeTimer.removeEventListener(TimerEvent.TIMER, arguments.callee); 

       // break out 
       return self.alpha = 1; 

      // timer 
      case TimerEvent.TIMER: 
       return self.alpha += 0.1; 

     } 
    } 

    fadeTimer.addEventListener(TimerEvent.TIMER, handler); 
    fadeTimer.addEventListener(TimerEvent.TIMER_COMPLETE, handler); 
    fadeTimer.start(); 

} 
+0

Guau, eso es completamente genial! Gracias, increíble cómo nunca pensé en usar callee de esa manera ... Pero si funciona debería haber sido una práctica muy popular, ¿verdad ?, ¿realmente hace un trabajo, has probado? ¿Hay alguna advertencia oculta? – jayarjo

+1

advertencia oculta es que no es recomendable. Hice una prueba hace un par de días y funcionó bien, aunque todavía no lo veo como la "gran" opción. Creo que los miembros de la clase son la mejor manera de hacerlo. Deberías buscar el objeto de los rasgos: básicamente es un objeto interno oculto que permite el flash hacer una búsqueda rápida de los miembros. A todos les gusta agrupar un grupo de controladores junto con el evento de cambio para facilitar el manejo de eventos. Este tipo de código solo está pidiendo que se haga una clase de utilidad. – ansiart

Cuestiones relacionadas