答案是……事件处理。
但首先,让我们了解一下,什么是事件以及我们为什么需要它们。
Flash Player 是一个平台,它以特定的逐帧方式运行其应用程序,无休止地重复相同的循环:
- 执行脚本(MovieClip的帧脚本以及自上一帧以来发生的所有事件)。
- 渲染显示列表(其中包括脚本执行的结果以及通过设计逐帧更改的内容,例如 MovieClip 的时间线)并显示渲染结果。李>
在脚本执行阶段结束之前,渲染阶段不会开始。如果你放一些无限运行的脚本,渲染阶段根本不会开始:
while (true)
{
// Do nothing.
}
它与套接字有什么关系?问题是,有些操作(大部分与外部环境有关)不能保证在给定时间内完成(或根本完成):
- 从本地驱动器加载文件。
- 通过 HTTP 请求发送和接收数据。
- (以及)连接到 TCP 套接字,向/从其发送和接收数据。
如果您在脚本执行阶段尝试等待这些(和其他类似)操作完成,您可能会完全停止您的应用程序。
那么,你如何避免这样的结局呢?
答案是:异步操作和事件。什么是异步?与上述主要 Flash Player 循环并行运行的操作。
您应该以类似多线程的方式进行思考,并将您的 AS3 逻辑组合在一小段代码中,这些代码开始非保证操作并完成脚本以允许渲染阶段发生,而其他代码块在WHEN出现时执行,而这些长时间运行的非保证操作执行它们的操作。重要的是它并不重要,WHEN。我们只是假设它发生在一段时间后。
让我们看一些例子:
// WARNING: This one snippet is NOT a real AS3 code,
// just an example of synchronous thinking.
function loadSettings(fileName:String):void
{
var aSettings:String = LocalFile.load(fileName);
if (aSettings)
{
// The file was loaded successfully, process the loaded data.
}
else
{
// The file failed to load. React to it.
}
}
那么,在AS3中是如何做到的:
function loadSettings(fileName:String):void
{
// Here I let the aLoader be a local function variable,
// yet keep in mind that you ALWAYS need to store such
// an object attached to scope in some way. Otherwise
// the Garbage Collector might just eat it away.
var aLoader:URLLoader = new URLLoader;
// Subscribe to events of the loading process.
// Successful loading.
aLoader.addEventListener(Event.COMPLETE, onSettings);
// Error cases.
aLoader.addEventListener(IOErrorEvent.IO_ERROR, onFailed);
aLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onFailed);
// Start asynchronous loading process.
aLoader.load(new URLRequest(fileName));
// The script is done here.
}
让我们处理这些事件。
function onSettings(e:Event):void
{
// Event ALWAYS has a reference to the object,
// but you need to typecast it to the appropriate class.
var aLoader:URLLoader = e.target as URLLoader;
// The file was loaded successfully, process the loaded data.
}
function onFailed(e:Event):void
{
var aLoader:URLLoader = e.target as URLLoader;
// The file failed to load. React to it.
}
如您所见,这两种情况的逻辑完全相同,但事件处理允许文件加载根据需要花费尽可能多的时间,而不会导致 Flash Player 卡顿。
我还鼓励您搜索类似 as3 events Explained 的内容并阅读所有相关教程。
使用您的插座,情况完全相同。您有几个可能有效的 host:port 对,您希望您的脚本连接到任何可用的,您需要停止单线程思考并开始思考 events:
var aSock:Socket;
var aList:Array = [
{host:"127.0.0.1", port:1000},
{host:"127.0.0.1", port:1236},
{host:"129.124.7.17", port:1000},
];
function tryNext():void
{
// Create a new socket instance.
aSock = new Socket;
// Subscribe to possible outcomes.
aSock.addEventListener(Event.CONNECT, onConnected);
aSock.addEventListener(IOErrorEvent.IO_ERROR, onFailed);
aSock.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onFailed);
// Try connecting to the next server from the list.
var aServer:Object = aList[0];
// Start the asynchronous operation.
aSock.connect(aServer.host, aServer.port);
}
// Handle the failed-to-connect case.
function onFailed(e:Event):void
{
// Sanity check: ignore the event, if
// it is not from the current socket object.
var aSocket:Socket = e.target as Socket;
if (aSocket != aSock) return;
// Remove the failed server from the list.
aList.shift();
// Try next server, if there are any left.
if (aList.length)
{
tryNext();
}
else
{
// None of the given servers responded.
// Process the case here.
}
}
// Handle the failed-to-connect case.
function onConnected(e:Event):void
{
// Sanity check, again.
var aSocket:Socket = e.target as Socket;
if (aSocket != aSock) return;
// If we're here, that means everything is fine and the socket aSock
// is successfully connected to the server with the host:port pair
// from the aList[0] object. You can start reading and writing
// data from/to socket from here on.
}