我从JS世界来到AS3,我应该承认匿名函数是我的弱点。我倾向于到处使用它们。现在,来到AS3我已经听过很多地方的内容,AS和Flash在处理垃圾收集时非常糟糕,应该清空,处理和删除所有事件处理程序和对象,以避免奇怪和无法解释的内存泄漏崩溃。不确定这部分是什么,但我想从一开始就遵循最佳实践。
所以我的问题是 - 使用匿名函数作为事件处理程序的想法有多糟糕?考虑一下这样的代码:
addEventListener(Event.ENTER_FRAME, function() : void {
controls.elapsed = stream.time;
});
contorls.elapsed 是设置者,除了设置视频播放器的当前播放时间外,还会更新整个用户界面,流是 NetStream object,它传输实际视频。
有很多其他地方匿名功能可以使代码更清晰,更直观。检查以下代码以获得控制栏的简单淡入效果:
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();
}
}
我完全喜欢它的外观和适合代码,但我担心泄漏。虽然Event.ENTER_FRAME处理程序可能永远不会在这种形式中变得有害,但计时器监听器呢。如果我设置 fadeTimer = null ,我应该手动删除这些侦听器,还是会自动删除它们?是否可以正确删除具有匿名功能的侦听器?
答案 0 :(得分:7)
刚刚注意到这篇文章 - 有几件事可能对你有用。一个是arguments.callee(它是对你当前函数的引用)。这对于删除匿名函数中的引用很有用。此外,可以注意到可能在addEventListener代码中使用弱引用 - 但是,这对于匿名变量不起作用,因为它们几乎立即得到了GC。为简单起见,我重写了这样的代码:(应该工作 - 没有测试过)
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();
}
答案 1 :(得分:3)
我会这样做的。并且,如果要确保在中断时清除计时器,请务必使用dispose()。
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;
}
}
答案 2 :(得分:2)
使用函数方法可以正常工作。就内存泄漏而言,您需要跟踪舞台上的对象以查看是否可以删除它。
向控件添加ENTER_FRAME
事件处理程序可确保控件具有对匿名函数的引用。由于代码是控件的一部分(或者它出现),这很好,因为当控件被删除时,匿名函数将被删除。
向计时器添加事件处理程序可确保计时器具有对匿名函数的引用。如果计时器正在运行,它将使匿名函数引用保持活动状态,并通过关联保持enture控件。但是,一旦计时器停止,它和功能都应该被收集。
如果所有其他方法都失败了,请使用探查器并查看! ;)