Flash的fl组件和Flex的mx组件都有一个受保护方法callLater,callLater可以说是优化组件执行效率的一个杀手锏,极其有用。
拿Flash的fl组件为例,fl组件有个重绘方法redraw(),如果改变组件的大小,焦点的获得和丢失都会是组件重绘来呈现不同的状态。而组件是复杂的,重绘的开销很大。如果假想一个按钮执行以下程式来更改外观,并且每次的更改都触发redraw()方法执行,那它将执行3次重绘,很显然是不须要的。
button.
width=
200;
button.
height=
28;
button.
setStyle("textFormat",myTextFormat
);
一个优化的方式是假设组件不会自动重绘,需要手动进行:
button.
width=
200;
button.
height=
28;
button.
setStyle("textFormat",myTextFormat
);
button.redraw
();
这个方式不太友好,每次都要记得去重绘组件,幸运的是callLater解决了这个问题。
callLater把要执行的函数延迟到下一帧。所以对button的width更改后,它会记得在下一帧重绘自身,当然这一帧你还改变了height和样式,它也只是重复地记忆要在下一帧重绘自身。到了下一帧的时候,它执行一次redraw(),仅是一次。
Flex组件的基类UIComponent有110多个公开属性,90个公开方法,17个受保护方法,70多个事件,10多个样式,10多个效果,还有6个常量。一个基类都如此庞大,可想而知,优化是多么重要。
在Flex组件的callLater中,重绘被分割成了三个受保护的方法:
commitProperties()measure()updateDisplayList()职责的分割更加提高了效率,这些延迟执行都是callLater实现的。把callLater实现的细节抽取下来写成一个单独的类:
package com.colorhook.tools
{ /**
* @author colorhook
* @copyright http://www.colorhook.com
*/
import flash.display.
DisplayObject;
import flash.utils.
Dictionary;
import flash.events.
Event;
public class FrameCallLater implements ICallLater
{
private var _target
:DisplayObject;
private var methods
:Dictionary;
private var inCallLaterPhase
:Boolean=
false;
public function FrameCallLater
(target:DisplayObject){ this._target=
target;
methods=
new Dictionary(true);
super();
}
/**
* defined by ICallLater, I write a class TimeCallLater to implement it also.
*/
public function call(fun
:Function):void{ if (inCallLaterPhase
||_target==
null) { return;
}
methods
[fun
]=
true;
if (_target.
stage !=
null) { _target.
stage.
addEventListener(Event.
RENDER,callLaterDispatcher,
false,
0,
true);
_target.
stage.
invalidate();
} else { _target.
addEventListener(Event.
ADDED_TO_STAGE,callLaterDispatcher,
false,
0,
true);
} }
private function callLaterDispatcher
(event
:Event):void { if (event.
type ==
Event.
ADDED_TO_STAGE) { _target.
removeEventListener(Event.
ADDED_TO_STAGE,callLaterDispatcher
);
_target.
stage.
addEventListener(Event.
RENDER,callLaterDispatcher,
false,
0,
true);
_target.
stage.
invalidate();
return;
} else { event.
target.
removeEventListener(Event.
RENDER,callLaterDispatcher
);
if (_target.
stage ==
null) { _target.
addEventListener(Event.
ADDED_TO_STAGE,callLaterDispatcher,
false,
0,
true);
return;
} }
inCallLaterPhase =
true;
for (var method:Object in methods
) { method();
delete(methods
[method]);
} inCallLaterPhase =
false;
}
public function get target():DisplayObject{ return_target;
}} }
分享到: