关于Actionscript3的事件驱动代码执行机制

    近来写代码的时候,常常会担心代码的执行顺序,例如某个函数是否会被事件处理函数打断之类的,百度了一下,无果(这个已经早就预料到的了),关键时候还是得翻出我的英语老底,投靠google吧。

以下是我自己设计的测试场景:

测试场景1:
  假设有类ExecutionTest, 代码如下:
  package com.longpeijin.exec
{
	import flash.display.Sprite;
	import flash.events.Event;
	
	public class ExecutionTest extends Sprite
	{
		public function ExecutionTest()
		{
			var obj:SystemHandler = new SystemHandler(this,"1");
			var obj1:SystemHandler = new SystemHandler(this,"2");
			this.dispatchEvent(new Event(SystemHandler.SYS_EVENT));
			trace("Main function executed!");
		}
	}
}


和另外一个类SystemHandler:
package com.longpeijin.exec
{
	import flash.events.Event;
	import flash.events.EventDispatcher;

	public class SystemHandler
	{
		public static const SYS_EVENT:String = "sysEvent";
		private var name:String;
		
		public function SystemHandler(obj:EventDispatcher, name:String)
		{
			obj.addEventListener(SYS_EVENT,onEvent);
			this.name = name;
		}
		
		public function onEvent(event:Event):void{
			trace("event handler executed! " + name);
		}
	}
}


  简单来说就是ExecutionTest类的某个方法在执行的过程中发布了一次事件,紧接着其后又执行了一些代码,那么监听这个事件的事件处理程序会马上执行还是等待ExecutionTest执行完毕才执行呢?

输出结果如下:
event handler executed! 1
event handler executed! 2
Main function executed!


结果可以知道,在执行过程中发布一次时间,其实就是在事件监听链条上逐个执行事件处理程序,然后再返回主函数,跟普通的函数调用没有两样!

所以ExecutionTest类的构造函数等价于以下的样子:
package com.longpeijin.exec
{
	import flash.display.Sprite;
	import flash.events.Event;
	
	public class ExecutionTest extends Sprite
	{
		public function ExecutionTest()
		{
			var obj:SystemHandler = new SystemHandler(this,"1");
			var obj1:SystemHandler = new SystemHandler(this,"2");
			obj.onEvent(null);
			obj1.onEvent(null);
			trace("Main function executed!");
		}
	}
}


测试场景2:

   另外一个我想知道的问题就是,假如有一个函数正在执行一个比较耗时的操作,这时候其他的一个对象发出了一次事件(例如一个网络资源下载完成了),而自身也有监听这个事件,那么这时当前函数的执行会被打断么?

于是我设计了以下的类EventTest:
package com.longpeijin.event
{
	import flash.display.Loader;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.net.URLRequest;
	
	public class EventTest extends MovieClip
	{
		public function EventTest()
		{
			super();
			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
			loader.load(new URLRequest("http://www.evolife.cn/wp-content/uploads/2010/06/iphone4display3.jpg"));
			this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
			this.stage.frameRate = 20;
		}
		
		
		
		private function onEnterFrame(event:Event):void{
			trace("On Enter frame start!");
			//do something time consuming
			var arr:Array = [];
			for(var i:int;i<10000;i++){
				arr.push(Math.random());
			}
			for each(var num:int in arr){
				Math.sqrt(num*100);
			}
			trace("On Enter frame end!");
		}
		
		private function onComplete(event:Event):void{
			trace("Resouces loaded!");
		}
	}
}


为了排除网络速度因素,我执行了该类10次,但每次的输出都有一个固定的片段:
On Enter frame start!
On Enter frame end!
Resouces loaded!
On Enter frame start!
On Enter frame end!

Resouces loaded!没有一次出现在On Enter frame start!和On Enter frame end!之间,换句话说,函数从来没有被打断过。

    之前也求教过一些高手,得知Flash的代码执行线程只有一个(这里指的是执行代码的线程,不包括下载网络资源的那些线程),有点类似底层CPU的时间片轮转执行,但轮转的并不是线程(因为主线程只有一个),而是各个对象的事件处理函数(Timer事件,Event.Complete事件,KeyboardEvent之类的),所以AVM的执行完全是事件驱动的。即使主MovieClip的构造函数(类似于Java中的main方法)执行完毕,程序不会像普通Java程序那样直接退出,而是空闲着等待着事件的发生,而且函数的执行是原子性的,任何时候不会被打断(除非AVM被崩掉或者你叉掉浏览器啦)。
    换个角度来看Flash是不支持多线程的,所以6核、双核、单核的CPU执行起来,都只会用到其中的一个核心而已。

    上面的探讨如有任何错误或疑惑,欢迎回复指正和讨论。

你可能感兴趣的:(多线程,浏览器,百度,Google,Flash)