Browse > Home > Archive: 八月 2007

| Subcribe via RSS

谈谈AS中的惰性函数模式(Lazy Function Definition)

八月 31st, 2007 | No Comments , 182 views | Posted by flashlizi in Flash8/AS2

最近看了Peter的Javascript的惰性函数定义模式(Lazy Function Definition)之后,想测试下as下的这种函数模式的效率是否比一般的模式要高。不了解此函数定义模式的朋友可以看看这篇文章的翻译。我做了如下测试:
[code]
//普通函数模式
var num = 0;
function test1() {
return num++;
}
//惰性函数模式
var test2 = function () {
var num = 0;
test2 = function () {
return num++;
};
return num++;
};
getTime1();
getTime2();
function getTime1() {
var time = getTimer();
for (var i:Number = 0; i < 1e+5; i++) {
test1();
}
trace("test1调用次数:" + test1());
trace("普通函数模式:" + (getTimer() - time));
}
function getTime2() {
var time = getTimer();
for (var i:Number = 0; i < 1e+5; i++) {
test2();
}
trace("test2调用次数:" + test2());
trace("惰性函数模式:" + (getTimer() - time));
}
[/code]
在我的机器上的测试结果是普通函数模式运行10万次的时间为825ms左右,惰性函数模式则为790ms左右。从效率上来看,2种模式基本差不多,但惰性模式有它的优点:省略了多余的全局变量num,而且可以防止变量num在函数外部被修改,效率方面也有些提升,还是值得使用的。

然而当我想测试as3下是否也这样的时候,却得到了一个惊人结果:普通函数模式运行100万次的时间为110ms左右,惰性函数模式为320ms左右。显然有一个结论是,在as3下,这种惰性函数模式效率比普通模式低了很多,是否要应用这种函数模式就值得商榷了。但是大家看清楚刚才的测试,as2下是10万次而as3下是100万次。。。它们之间的差距我只能用天壤之别来形容了。呵呵,看到这里,是不是让大家更有信心投入到as3的怀抱中呢?

FlashTail:简单实用的actionscript调试工具

八月 27th, 2007 | No Comments , 205 views | Posted by flashlizi in Flash CS3/AS3

Flash player的debuger版本有个功能,可以把flash文件中的trace信息输出到一个名为flashlog.txt的文本文件中,而且不管当前运行的flash所在的域如何或者是嵌在其他应用程序中,这些trace信息一律都会被记录在flashlog.txt中。因此我们可以利用这一特性,调试其他flash调试工具无法调试的flash程序。

首先要确认你的机器里安装了Flash player的debuger版本,检测办法:访问这里,右键点击中间那个flash(文字:Adobe Flash Player is installed.),如果在右键菜单中有“debuger”或者“调试器”的选项,则说明你已经安装了debuger版本。一般的如果你安装了flash 8或者flash cs3的话,都会自动安装了debuger版本。

接下来,新建一个mm.cfg文件。地址为:C:\Documents and Settings\username\mm.cfg,其中username为你的XP系统用户名,比如Administrator。打开mm.cfg,输入:

ErrorReportingEnable=0
TraceOutputFileEnable=1

然后,创建一个flashlog.txt文件。地址为:C:\Documents and Settings\username\Application Data\Macromedia\Flash Player\Logs\flashlog.txt,其中Logs目录需要自己创建的。这样,你机器上的flash文件里的trace信息就会保存在此文件中。但是,需要注意的是此文件只会保存最后打开的flash文件的trace信息。

为了使用方便,我做了一个监控和读取flashlog.txt文件内容的小工具:FlashTail。在你调试的时候,只要先把它打开,然后再打开需要调试的flash,FlashTail中就会把你的trace信息都显示出来。简单又非常方便,无需像其他debuger工具那样要在flash中添加调试代码,只需简单的trace()就OK!

AS3的一些优化计算方法

八月 13th, 2007 | 1 Comment , 228 views | Posted by flashlizi in Flash CS3/AS3

今天在John Grden的Blog上看到一篇关于AS3优化计算的文章:Optimizations for AS3 calculations,觉得不错,把其中的一些方法记录下来。

1、用乘法来代替除法(当除数可转化为有限数的时候)。比如var n:Number = value *0.5;要比var n:Number = value / 2;快。但差别并不是很大。只有在需要大量计算情况下,比如3D引擎中差别才比较明显。

2、用位运算代替除2或乘2。比如10>>1要比10*2快,而10<<1要比10*2快。从测试来看位运算几乎比乘除快一倍,但是一般情况下,我们不能选择位运算,比如我们就不能用13>>1来代替13/2,尽管前者比后者运算速度更快,但2者的运算结果却不一样。所以还是要看具体情况。

3、用unit()或int()代替取整运算Math.floor()和Math.ceil()。比如var test:uint = uint(1.5);要比var test:Number = Math.floor(1.5);快;而var test:uint = uint(1.5)+1;要比var test:Number = Math.ceil(1.5);也快。如果是Math.floor(),还可以用位运算(>>0)来代替。比如var test:uint =1.5>>0,比unit()或int()更快。

4、用乘-1来代替Math.abs()方法。比如var nn:Number = -23;var test:Number= nn < 0 ? nn * -1 : nn;要比var nn:Number = -23;var test:Number = Math.abs(nn);快。

当然还有更多的优化计算的方法。一般来说,低级运算要比高级运算速度;内部方法比调用其他方法速度快。另外要注意的是,这些方法有的时候可能并一定适用。

附上测试代码:
[code]import flash.utils.getTimer;
var time:Number = getTimer();
function runDivisionTest():void {
time = getTimer();
for (var i:Number=0; i<10000000; i++) {
var test:Number = i/2;
}
trace("DivisionTest: ", (getTimer()-time));
}
function runMultTest():void {
time = getTimer();
for (var i:Number=0; i<10000000; i++) {
var test:Number = i*.5;
}
trace("MultTest: ", (getTimer()-time));
}
function runBitTest():void {
time = getTimer();
for (var i:int=0; i<10000000; i++) {
var test:int = i>> 1;
}
trace("BitTest: ", (getTimer()-time));
}
function runFloorTest():void {
time = getTimer();
for (var i:uint=0; i<10000000; i++) {
var n:Number = 1.5;
var test:Number = Math.floor(n);
}
trace("FloorTest: ", (getTimer()-time));
}
function runUintTest():void {
time = getTimer();
for (var i:uint=0; i<10000000; i++) {
var n:Number = 1.5;
var test:uint = uint(n);
}
trace("UintTest: ", (getTimer()-time));
}
function runCeilTest():void {
time = getTimer();
for (var i:uint=0; i<10000000; i++) {
var n:Number = 1.5;
var test:Number = Math.ceil(n);
}
trace("CeilTest: ", (getTimer()-time));
}
function runUintCeilTest():void {
time = getTimer();
for (var i:uint=0; i<10000000; i++) {
var n:Number = 1.5;
var test:uint = n == uint(n) ? n : uint(n)+1;
}
trace("UintCeilTest: ", (getTimer()-time));
}
function runABSTest():void {
time = getTimer();
for (var i:uint=0; i<10000000; i++) {
var n:Number = -1.5;
var test:Number = Math.abs(n);
}
trace("ABSTest: ", (getTimer()-time));
}
function runABSMultTest():void {
time = getTimer();
for (var i:uint=0; i<10000000; i++) {
var n:Number = -1.5;
var test:Number = n <0 ? n * -1 : n;
}
trace("ABSMultTest: ", (getTimer()-time));
}
runDivisionTest();
runMultTest();
runBitTest();
runFloorTest();
runUintTest();
runCeilTest();
runUintCeilTest();
runABSTest();
runABSMultTest();[/code]

AS2:让flash捕获用户的快捷键动作

八月 10th, 2007 | No Comments , 210 views | Posted by flashlizi in Flash8/AS2

一般情况下,大家都知道要让flash捕获用户的按键动作可以使用Key类中的onKeyDown、onKeyUp事件以及Key.isDown()、Key.getCode()和Key.getAscii()等方法来实现。这里说一下如何捕获一些组合键(如ctrl+s)?下面是一段捕获ctrl+s快捷键的AS2代码:
[code]var keyListener:Object = new Object();
keyListener.onKeyDown = function() {
trace(Key.getCode());
if (Key.isDown(Key.CONTROL) && Key.getCode() == 83) {
txt.text = "ctrl+s";
}
};
Key.addListener(keyListener);[/code]
在上面代码中,当用户按下ctrl+s快捷键的时候,文本字段txt中的文本就会变成ctrl+s,表示我们已经正常捕获ctrl+s快捷键了。注意:在flash中测试影片(ctrl+enter)的时候一定要在控制中把禁用快捷键勾上,否则测试无效。

但是有些快捷键,如ctrl+C、ctrl+F等,用上面的方法仍然无法捕获。这是因为这些快捷键已经被flash player首先给捕获做其他用途了,当然就无法传到里面的处理函数了。因此我们要告诉flash player释放这些快捷键给AS使用,幸好fscommand函数的trapallkeys命令可以实现这个目的,具体代码为:
fscommand("trapallkeys", true);

这样要实现ctrl+C快捷键,就只要在上面捕获ctrl+s快捷键的AS2代码中加上这条语句就可以了。不过注意这条语句在flash中测试影片(ctrl+enter)的时候是无效的,因为这些快捷键被flash IDE捕获,要单独运行swf文件才有效。具体代码为:
[code]fscommand("trapallkeys", true);
var keyListener:Object = new Object();
keyListener.onKeyDown = function() {
trace(Key.getCode());
if (Key.isDown(Key.CONTROL) && Key.getCode() == 67) {
txt.text = "ctrl+c";
}
};
Key.addListener(keyListener);[/code]

Function类的call方法的深入研究

八月 3rd, 2007 | No Comments , 202 views | Posted by flashlizi in Flash CS3/AS3

从as1,2开始Function类就有call和apply2个方法了。相信大家对这2个方法的应该有一些了解,这2个方法的第一个参数thisObject在有些时候很有用,合理利用他们可以使函数表现得像另一个对象的方法,而不将函数存储在该对象中。
比如官方帮助中的一个例子:
[code]
function myObject() {
}
function myMethod(obj) {
trace("this == obj? " + (this == obj));//trace() 语句将显示:this == obj? true

}
var obj:Object = new myObject();
myMethod.call(obj, obj);
[/code]

但是到了as3,this始终指向函数所属的对象。上面的例子在as3中是不成立的。那是不是说call方法中的thisObject在as3中失去了意义了呢?下面的例子说明在某些情况下还是有他的用处的:
这是一个documentClass:
[code]
package {
import flash.display.Sprite;
public class FunctionCallExample extends Sprite {
public function FunctionCallExample() {
var test1=new TestA();
var test2=new TestB();
//不管传入对象X的function的call的参数指向任何对象,
//function中的this永远都指向原对象X。
test1.callA.call(this);
//如果给callB传入的参数是一个对象X中已定义的方法,
//那么这个方法中的this永远都指向此对象X。
test2.callB(test1.callA);
//当给CallB传入的参数是一个不知所属的function的时候,
//此时这个function中的this才会由call中指向的对象来确定。
test2.callB(function(){trace(this)});
}
}
}
internal class TestA {
public function callA() {
trace(this);
}
}
internal class TestB {
public function callB(fn:Function) {
fn.call(this);
fn.call(TestA);
}
}
[/code]

通过上面的测试,我们发现,只有当function不知所属(即在参数中定义的函数)的时候,其中的this才会受call方法的thisObject参数控制。其他时候function中的this一律指向他所属的对象或类。同样的,apply方法也类似。