Cuando se utiliza un objeto proveedor de datos asíncrono, la propiedad
isAsync
de IFilePromise se debe establecer en
true
y el objeto devuelto por el método
open()
debe implementar la interfaz IEventDispatcher. El motor de ejecución detecta varios eventos alternativos de modo que los distintos objetos incorporados se puedan utilizar como proveedores de datos. Por ejemplo, los eventos
progress
se distribuyen mediante los objetos FileStream y URLStream, mientras que los eventos
socketData
se distribuyen a través de los objetos Socket. El motor de ejecución detecta los eventos apropiados a partir de todos estos objetos.
Los siguientes eventos controlan el proceso de lectura de datos desde el objeto proveedor:
-
Event.OPEN: informa al motor de ejecución de que el origen de datos está listo.
-
ProgressEvent.PROGRESS: indica al motor de ejecución que los datos están disponibles. El motor de ejecución leerá la cantidad de datos disponibles desde el objeto proveedor de datos.
-
ProgressEvent.SOCKET_DATA: indica al motor de ejecución que los datos están disponibles. El evento
socketData
se distribuye mediante los objetos basados en socket. Para otros tipos de objetos, se debe distribuir un evento
progress
. (El motor de ejecución detecta ambos eventos para percibir el momento en que se pueden leer los datos.)
-
Event.COMPLETE: indica al motor de ejecución que todos los datos se han leído.
-
Event.CLOSE: indica al motor de ejecución que todos los datos se han leído. (El motor de ejecución detecta
close
y
complete
para este propósito.)
-
IOErrorEvent.IOERROR: indica al motor de ejecución que se ha producido un error al leer los datos. El motor de ejecución anula la creación del archivo y llama al método
close()
de IFilePromise.
-
SecurityErrorEvent.SECURITY_ERROR: indica al motor de ejecución que se ha producido un error de seguridad. El motor de ejecución anula la creación del archivo y llama al método
close()
de IFilePromise.
-
HTTPStatusEvent.HTTP_STATUS: el motor de ejecución lo utiliza, junto con
httpResponseStatus
, para garantizar que los datos disponibles representan el contenido deseado, en lugar de un mensaje de error (por ejemplo, una página 404). Los objetos basados en el protocolo HTTP deben distribuir este evento.
-
HTTPStatusEvent.HTTP_RESPONSE_STATUS: el motor de ejecución lo utiliza, junto con
httpStatus
, para garantizar que los datos disponibles representan el contenido deseado. Los objetos basados en el protocolo HTTP deben distribuir este evento.
El proveedor de datos debe distribuir estos eventos en la siguiente secuencia:
-
evento
open
-
eventos
progress
o
socketData
-
evento
complete
o
close
Nota:
los objetos incorporados, FileStream, Socket y URLStream distribuyen los eventos adecuados de forma automática.
En el siguiente ejemplo se crea una promesa de archivo utilizando un proveedor de datos asíncrono y personalizado. La clase del proveedor de datos amplía ByteArray (para la compatibilidad con IDataInput) e implementa la interfaz IEventDispatcher. En cada evento del temporizador, el objeto genera un campo de datos y distribuye un evento de progreso para indicar al motor de ejecución que los datos están disponibles. Una vez generados datos suficientes, el objeto distribuye un evento completo.
package
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.ProgressEvent;
import flash.events.TimerEvent;
import flash.utils.ByteArray;
import flash.utils.Timer;
[Event(name="open", type="flash.events.Event.OPEN")]
[Event(name="complete", type="flash.events.Event.COMPLETE")]
[Event(name="progress", type="flash.events.ProgressEvent")]
[Event(name="ioError", type="flash.events.IOErrorEvent")]
[Event(name="securityError", type="flash.events.SecurityErrorEvent")]
public class AsyncDataProvider extends ByteArray implements IEventDispatcher
{
private var dispatcher:EventDispatcher = new EventDispatcher();
public var fileSize:int = 0; //The number of characters in the file
private const chunkSize:int = 1000; //Amount of data written per event
private var dispatchDataTimer:Timer = new Timer( 100 );
private var opened:Boolean = false;
public function AsyncDataProvider()
{
super();
dispatchDataTimer.addEventListener( TimerEvent.TIMER, generateData );
}
public function begin():void{
dispatchDataTimer.start();
}
public function end():void
{
dispatchDataTimer.stop();
}
private function generateData( event:Event ):void
{
if( !opened )
{
var open:Event = new Event( Event.OPEN );
dispatchEvent( open );
opened = true;
}
else if( position + chunkSize < fileSize )
{
for( var i:int = 0; i <= chunkSize; i++ )
{
writeUTFBytes( 'A' );
}
//Set position back to the start of the new data
this.position -= chunkSize;
var progress:ProgressEvent =
new ProgressEvent( ProgressEvent.PROGRESS, false, false, bytesAvailable, bytesAvailable + chunkSize);
dispatchEvent( progress )
}
else
{
var complete:Event = new Event( Event.COMPLETE );
dispatchEvent( complete );
}
}
//IEventDispatcher implementation
public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
{
dispatcher.addEventListener( type, listener, useCapture, priority, useWeakReference );
}
public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
{
dispatcher.removeEventListener( type, listener, useCapture );
}
public function dispatchEvent(event:Event):Boolean
{
return dispatcher.dispatchEvent( event );
}
public function hasEventListener(type:String):Boolean
{
return dispatcher.hasEventListener( type );
}
public function willTrigger(type:String):Boolean
{
return dispatcher.willTrigger( type );
}
}
}
Nota:
debido a que la clase AsyncDataProvider del ejemplo amplía ByteArray, no puede ampliar también EventDispatcher. Para implementar la interfaz IEventDispatcher, la clase utiliza un objeto interno EventDispatcher y reenvía las llamadas del método IEventDispatcher a ese objeto interno. También se puede ampliar EventDispatcher e implementar IDataInput (o implementar ambas interfaces).
La implementación asíncrona de IFilePromise resulta casi idéntica a la implementación sincrónica. Las principales diferencias radican en que
isAsync
devuelve el valor
true
y que el método
open()
devuelve un objeto de datos asíncrono:
package
{
import flash.desktop.IFilePromise;
import flash.events.ErrorEvent;
import flash.events.EventDispatcher;
import flash.utils.IDataInput;
public class AsynchronousFilePromise extends EventDispatcher implements IFilePromise
{
private var fileGenerator:AsyncDataProvider;
private const fileSize:int = 5000; //size of file data
private var filePath:String = "AsynchronousFile.txt";
public function get relativePath():String
{
return filePath;
}
public function get isAsync():Boolean
{
return true;
}
public function open():IDataInput
{
fileGenerator = new AsyncDataProvider();
fileGenerator.fileSize = fileSize;
fileGenerator.begin();
return fileGenerator;
}
public function close():void
{
fileGenerator.end();
}
public function reportError(e:ErrorEvent):void
{
trace("Something went wrong: " + e.errorID + " - " + e.type + ", " + e.text );
}
}
}