论坛交流
首页办公自动化| 网页制作| 平面设计| 动画制作| 数据库开发| 程序设计| 全部视频教程
应用视频: Windows | Word2007 | Excel2007 | PowerPoint2007 | Dreamweaver 8 | Fireworks 8 | Flash 8 | Photoshop cs | CorelDraw 12
编程视频: C语言视频教程 | HTML | Div+Css布局 | Javascript | Access数据库 | Asp | Sql Server数据库Asp.net  | Flash AS
当前位置 > 文字教程 > Flash AS编程教程
Tag:2.0,3.0菜鸟,游戏,,cs,技巧,源码,,文本,文字,函数,音乐,随机,拖拽,asp,access,xml,mc,视频教程

ActionScript处理异步事件(一)

文章类别:Flash AS编程 | 发表日期:2008-10-6 18:08:38


原文地址:http://kuwamoto.org/2006/05/16/dealing-with-asynchronous-events-part-1/
原文作者:ShoKuwamoto
译者:Dreamer

使用异步事件模型的一个困难就是很难写出易读的代码。这对于 AJAX 以及 Flex 应用程序都是同样真实的道理。

过去几个月以来,我针对这个问题尝试了各种各样的方法。我认为这能帮助我漫步在曾经尝试的各种代码中,并以此说明不同的方法。

让我们以RPC service 调用为例。假设我正在使用一个http service来获得一个唱片的信息:

public function getAlbumInfo(albumId: int) : void    
  1. {    
  2.       myService.request = { type: "album", albumId: albumId };    
  3.       myService.send();    
  4.       // I'd like to do something with the results of    
  5.       // my request, but I can't!    
  6. }  

问题是结果并不是立刻就返回。代码在执行而结果可能在数百毫秒内无法返回。

此外,Flash Player不提供一个阻滞的方法来等待结果就绪。为了相应最终返回的结果,你需要俘获一个事件。

public
 function getAlbumInfo(albumId: int) : void    
  1. {    
  2.       myService.addEventListener("result", getAlbumInfoResult);    
  3.       myService.request = { type: "album", albumId: albumId };    
  4.       myService.send();   
  5. }    
  6. public function getAlbumInfoResult(event: Event) : void    
  7. {    
  8.       // Hundreds of milliseconds later, my results    
  9.       // have arrived, and I can add them to my list!    
  10.       myAlbumList.addAlbum(event.result.album);    
  11. }   

这并不太差劲,是吗?现在,想象一下现在我需要在结果函数中使用albumId,而恰好RPC send()方法就有一个叫做呼叫对象(call object)的特殊对象来让我们那样做。

使用呼叫对象来传递参数

呼叫对象是一个一旦结果事件(result event)触发就会被传送到结果处理程序的对象。

public
 function getAlbumInfo(albumId: int) : void    
  1. {    
  2.       myService.addEventListener("result", getAlbumInfoResult);    
  3.       myService.request = { type: "album", albumId: albumId };    
  4.       // Make the call, and save a value for later use.    
  5.       var call : Object = myService.send();    
  6.       call.albumId = albumId;    
  7. }    
  8. public function getAlbumInfoResult(event: Event) : void    
  9. {    
  10.       // Use the albumId value that was passed to me from above    
  11.       // as part of the call object.    
  12.       myAlbumList.addAlbum(event.call.albumId, event.result.album);    
  13. }   

现在,假设我需要把这些呼叫串在一起。它会变得非常凌乱不堪。

public
 function getAlbumInfo(albumId: int) : void    
  1. {    
  2.       myService.addEventListener("result", getAlbumInfoResult);    
  3.       myService.request = { type: "album", albumId: albumId };   
  4.       // Save the albumId for use later!    
  5.       var call : Object = myService.send();    
  6.       call.albumId = albumId;    
  7. }    
  8. public function getAlbumInfoResult(event: Event) : void    
  9. {    
  10.       var artistId: int = event.result.album.artistId;    
  11.       myAlbumList.addAlbum(event.call.albumId, event.result.album);    
  12.       myService.addEventListener("result", getArtistInfoResult);    
  13.       myService.request = { type: "artist", artistId : artistId };    
  14.       // Now, save the artistId for use later!    
  15.       var call = myService.send();    
  16.       call.artistId = artistId;    
  17. }    
  18. public function getArtistInfoResult(event: Event) : void    
  19. {    
  20.       myArtistList.addArtist(event.call.artistId, event.result.artist);    
  21. }   

下面,让我们假设一种更复杂的情形:如果多个呼叫程序需要调用同一个HTTPservice呢?你如何确保正确地处理返回结果?

多个呼叫的问题

让我们把上面的代码做点简单的改变来阐明这个问题。

public
 function getAlbumInfo(albumId: int) : void    
  1. {    
  2.       // Wire up my result handler.    
  3.       myService.addEventListener("result", getAlbumInfoResult);    
  4.       // Ask for the album info.    
  5.       myService.request = { type: "album", albumId: albumId };    
  6.       myService.send();    
  7.       // Also ask for the album art.    
  8.       myService.request = { type: "albumArt", albumId: albumId };    
  9.       myService.send();   
  10. }    
  11. public function getAlbumInfoResult(event: Event) : void    
  12. {    
  13.       // At this point, I have no idea whether I should be    
  14.       // handling the album info or the album art.    
  15. }   

对这个问题的愚蠢的解决方法就是在第一个send之前绑定第一个函数,在第二个send之前绑定第二个函数:

public
 function getAlbumInfo(albumId: int) : void    
  1. {    
  2.       // Wire up my result handler.    
  3.       myService.addEventListener("result", getAlbumInfoResult);    
  4.       // Ask for the album info.    
  5.       myService.request = { type: "album", albumId: albumId };    
  6.       myService.send();    
  7.       // BUG!! This will not work!    
  8.       myService.removeEventListener("result", getAlbumInfoResult);    
  9.       myService.addEventListener("result", getAlbumArtResult);    
  10.       // Also ask for the album art.    
  11.       myService.request = { type: "albumArt", albumId: albumId };    
  12.       myService.send();    
  13. }   

如果你对异步编程很熟悉的话,你马上就会明白问题在哪里。对于那些不熟悉的人,这里列出了将会发生的事件的顺序:
1. 一个“result”的监听器(listener)将会绑定到 getAlbumInfoResult()。
2. 建立 album info请求。
3. 先前的监听器被移除。
4. “result”的一个新的监听器被绑定到 getAlbumArtResult()。
5. 建立 album art 请求。
6. 等待一段时间。
7. 由于网络没有任何规律,album info的结果返回或者是 album art 的结果返回。
8. 不管哪个呼叫返回,它都会找到 getAlbumArtResult()。因为这个时候它是唯一注册的监听器。

解决多个呼叫(mutiple call)的问题
解决多个呼叫问题的传统方法就是吧callback函数附加到呼叫对象上。这样可以正常工作,因为每次service被调用的时候一个唯一的呼叫对象就会被创建。

public
 function doInit()    
  1. {    
  2.       myService.addEventListener("result", handleResult);    
  3. }    
  4. public function getAlbumInfo(albumId: int) : void    
  5. {    
  6.       var call : Object;    
  7.       // Ask for the album info.    
  8.       myService.request = { type: "album", albumId: albumId };    
  9.       call = myService.send();    
  10.       call.handler = getAlbumInfoResult;    
  11.       // Also ask for the album art.    
  12.       myService.request = { type: "albumArt", albumId: albumId };    
  13.       call = myService.send();    
  14.       call.handler = getAlbumArtResult;    
  15. }    
  16. public function handleResult(event: ResultEvent) : void    
  17. {    
  18.       // Retrieve the call object from the event.    
  19.       var call : Object = event.call;    
  20.       // Get the handler.    
  21.       var handler : Function = call.handler;    
  22.       // Call the handler. We use handler.call(xxx) instead    
  23.       // of handler(xxx) to properly deal with the scope chain.    
  24.       handler.call(null, event);    
  25. }   

这在个新的代码中,两个对service的调用会呼叫同一个处理函数,但是实际上被呼叫的处理函数是隐藏在呼叫对象中的那个。在第一次呼叫的情况中,getAlbumInfoResult()将会被呼叫,而在第二种情况下,getAlbumArtResult()将会被呼叫。

待续...
视频教程列表
文章教程搜索
 
Flash AS推荐教程
Flash AS热门教程
看全部视频教程
购买方式/价格
购买视频教程: 咨询客服
tel:15972130058