You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@royale.apache.org by Harbs <ha...@gmail.com> on 2019/06/04 12:03:07 UTC

Re: [royale-asjs] branch develop updated: Added Async tasks

I finally got fed up enough with Promises et. al. that I broke down and wrote some Async classes which (IMO) are much easier to use.

AsyncTask needs to be subclassed. Here’s an implementation that I’m using in my app. If I find some time, I might create some HTTP tasks. I someone who’s better at docs than me wants to write something, that would be great. ;-)

package com.printui.utils
{
  import com.printui.model.vos.FontVO;
  import com.printui.model.proxies.FontProxy;

  public class LoadFontTask extends AsyncTask
  {
    public function LoadFontTask(font:FontVO)
    {
      super();
      this.font = font;
    }
    private var font:FontVO;
    override public function run(data:Object = null):void{
      var fp:FontProxy = ApplicationFacade.getInstance().retrieveProxy(FontProxy.NAME) as FontProxy;
      fp.loadNow(font,fontLoadDone);
    }
    private function fontLoadDone():void{
      if(font.embedded){
        complete();
      } else {
        fail();
      }
    }
  }
}

I’m using it like so:

    public function embedFonts(callback:Function):void{
      if(fontsEmbedded()){
        callback();
      } else {
        var tasks:Array = [];
        var font:FontVO = getAppliedFont();
        if(!font.embedded){
          tasks.push(new LoadFontTask(font));
        }
        font = getBulletFont();
        if(font && !font.embedded){
          tasks.push(new LoadFontTask(font));
        }
        var task:CompoundAsyncTask = new CompoundAsyncTask(tasks);
        task.done(function(task:AsyncTask):void{
          if(task.status == "complete"){
            // we're good
            callback();
          } else {
            // status is "failed" -- not sure what to do...
          }
        });
        task.run();
      } 
    }


> On Jun 4, 2019, at 2:55 PM, harbs@apache.org wrote:
> 
> This is an automated email from the ASF dual-hosted git repository.
> 
> harbs pushed a commit to branch develop
> in repository https://gitbox.apache.org/repos/asf/royale-asjs.git
> 
> 
> The following commit(s) were added to refs/heads/develop by this push:
>     new edb052c  Added Async tasks
> edb052c is described below
> 
> commit edb052cbf2fb1b9db276dff6e4a94ce0a7679f00
> Author: Harbs <ha...@in-tools.com>
> AuthorDate: Tue Jun 4 14:55:00 2019 +0300
> 
>    Added Async tasks
> ---
> .../CoreJS/src/main/config/compile-js-config.xml   |   1 +
> .../Core/src/main/config/compile-swf-config.xml    |   1 +
> .../Core/src/main/resources/basic-manifest.xml     |   3 +
> .../projects/Core/src/main/royale/CoreClasses.as   |   3 +
> .../royale/org/apache/royale/utils/ObjectMap.as    |  12 ++
> .../org/apache/royale/utils/async/AsyncTask.as     | 180 +++++++++++++++++++++
> .../apache/royale/utils/async/CompoundAsyncTask.as | 135 ++++++++++++++++
> .../royale/utils/async/SequentialAsyncTask.as      |  77 +++++++++
> 8 files changed, 412 insertions(+)
> 
> diff --git a/frameworks/js/projects/CoreJS/src/main/config/compile-js-config.xml b/frameworks/js/projects/CoreJS/src/main/config/compile-js-config.xml
> index bdc495e..e912e57 100644
> --- a/frameworks/js/projects/CoreJS/src/main/config/compile-js-config.xml
> +++ b/frameworks/js/projects/CoreJS/src/main/config/compile-js-config.xml
> @@ -71,6 +71,7 @@
>         </source-path>
> 
>         <warn-no-constructor>false</warn-no-constructor>
> +        <allow-abstract-classes>true</allow-abstract-classes>
> 
>         <!-- Use of the instanceof operator. -->
>         <warn-instance-of-changes>false</warn-instance-of-changes>
> diff --git a/frameworks/projects/Core/src/main/config/compile-swf-config.xml b/frameworks/projects/Core/src/main/config/compile-swf-config.xml
> index ecd4c77..265d4d8 100644
> --- a/frameworks/projects/Core/src/main/config/compile-swf-config.xml
> +++ b/frameworks/projects/Core/src/main/config/compile-swf-config.xml
> @@ -75,6 +75,7 @@
>         </source-path>
> 
>         <warn-no-constructor>false</warn-no-constructor>
> +        <allow-abstract-classes>true</allow-abstract-classes>
> 
>         <!-- Use of the instanceof operator. -->
>         <warn-instance-of-changes>false</warn-instance-of-changes>
> diff --git a/frameworks/projects/Core/src/main/resources/basic-manifest.xml b/frameworks/projects/Core/src/main/resources/basic-manifest.xml
> index ae4b7f7..f40d2e4 100644
> --- a/frameworks/projects/Core/src/main/resources/basic-manifest.xml
> +++ b/frameworks/projects/Core/src/main/resources/basic-manifest.xml
> @@ -52,4 +52,7 @@
>     <component id="StyleChangeNotifier" class="org.apache.royale.core.StyleChangeNotifier"/>
> 
>     <component id="State" class="org.apache.royale.states.State"/>
> +    
> +    <component id="CompoundAsyncTask" class="org.apache.royale.utils.CompoundAsyncTask">
> +    <component id="SequentialAsyncTask" class="org.apache.royale.utils.SequentialAsyncTask">
> </componentPackage>
> diff --git a/frameworks/projects/Core/src/main/royale/CoreClasses.as b/frameworks/projects/Core/src/main/royale/CoreClasses.as
> index 678df00..cdd9b25 100644
> --- a/frameworks/projects/Core/src/main/royale/CoreClasses.as
> +++ b/frameworks/projects/Core/src/main/royale/CoreClasses.as
> @@ -308,6 +308,9 @@ internal class CoreClasses
> 	import org.apache.royale.utils.date.addSeconds; addSeconds;
> 	import org.apache.royale.utils.date.addYears; addYears;
> 
> +	import org.apache.royale.utils.async.CompoundAsyncTask; CompoundAsyncTask;
> +	import org.apache.royale.utils.async.SequentialAsyncTask; SequentialAsyncTask;
> +
> 	import org.apache.royale.utils.css.addDynamicSelector; addDynamicSelector;
> 
> 	COMPILE::JS
> diff --git a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/ObjectMap.as b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/ObjectMap.as
> index d3bd5bc..836b76e 100644
> --- a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/ObjectMap.as
> +++ b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/ObjectMap.as
> @@ -157,9 +157,21 @@ package org.apache.royale.utils
> 
>         COMPILE::JS
>         {
> +            /**
> +             *  @royalesuppresspublicvarwarning
> +             */
>             public var get:Function = objectGet;
> +            /**
> +             *  @royalesuppresspublicvarwarning
> +             */
>             public var set:Function = objectSet;
> +            /**
> +             *  @royalesuppresspublicvarwarning
> +             */
>             public var has:Function = objectHas;
> +            /**
> +             *  @royalesuppresspublicvarwarning
> +             */
>             public var delete:Function = objectDelete;
>         }
> 
> diff --git a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/AsyncTask.as b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/AsyncTask.as
> new file mode 100644
> index 0000000..44a31ce
> --- /dev/null
> +++ b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/AsyncTask.as
> @@ -0,0 +1,180 @@
> +////////////////////////////////////////////////////////////////////////////////
> +//
> +//  Licensed to the Apache Software Foundation (ASF) under one or more
> +//  contributor license agreements.  See the NOTICE file distributed with
> +//  this work for additional information regarding copyright ownership.
> +//  The ASF licenses this file to You under the Apache License, Version 2.0
> +//  (the "License"); you may not use this file except in compliance with
> +//  the License.  You may obtain a copy of the License at
> +//
> +//      http://www.apache.org/licenses/LICENSE-2.0
> +//
> +//  Unless required by applicable law or agreed to in writing, software
> +//  distributed under the License is distributed on an "AS IS" BASIS,
> +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> +//  See the License for the specific language governing permissions and
> +//  limitations under the License.
> +//
> +////////////////////////////////////////////////////////////////////////////////
> +package org.apache.royale.utils.async
> +{
> +  import org.apache.royale.events.EventDispatcher;
> +  import org.apache.royale.events.Event;
> +
> +  /**
> +   * AsyncTask is a base class for AsyncTasks which let the caller know when they are done.
> +   * AsyncTask is an OOP replacement for Promises and simple callbacks which allows for
> +   * strongly typed async requests with any kind of payload and behavior.
> +   * AsyncTask must be subclassed to be used.
> +   * The subclass must implement the `run` method to define the behavior when the task is "run".
> +   */
> +
> +  [Event(name="complete", type="org.apache.royale.events.Event")]
> +  [Event(name="failed", type="org.apache.royale.events.Event")]
> +  [Event(name="done", type="org.apache.royale.events.Event")]
> +  public abstract class AsyncTask extends EventDispatcher
> +  {
> +    public function AsyncTask()
> +    {
> +
> +    }
> +    public static const INITIALIZED:String = "initialized";
> +    public static const PENDING:String = "pending";
> +    public static const COMPLETE:String = "complete";
> +    public static const CANCELED:String = "canceled";
> +    public static const FAILED:String = "failed";
> +    /**
> +     * Used in compound tasks
> +     */
> +    public static const MIXED:String = "mixed";
> +    protected var _status:String = "initialized";
> +    /**
> +     * One of: initialized, pending, complete, failed or mixed (for compound tasks)
> +     *  @langversion 3.0
> +     *  @playerversion Flash 10.2
> +     *  @playerversion AIR 2.6
> +     *  @productversion Royale 0.9.6
> +     */
> +    public function get status():String
> +    {
> +      return _status;
> +    }
> +    
> +    /**
> +     * completed (and a status of `complete`) means the task completed successfully
> +     *  @langversion 3.0
> +     *  @playerversion Flash 10.2
> +     *  @playerversion AIR 2.6
> +     *  @productversion Royale 0.9.6
> +     */
> +    public function get completed():Boolean
> +    {
> +    	return _status == "complete";
> +    }
> +    public function set completed(value:Boolean):void
> +    {
> +    	_status = "complete";
> +    }
> +
> +    /**
> +     * failed (and a status of `failed`) means the task resolved to a failed state
> +     *  @langversion 3.0
> +     *  @playerversion Flash 10.2
> +     *  @playerversion AIR 2.6
> +     *  @productversion Royale 0.9.6
> +     */
> +    public function get failed():Boolean
> +    {
> +    	return _status == "failed";
> +    }
> +    public function set failed(value:Boolean):void
> +    {
> +    	_status = "failed";
> +    }
> +    /**
> +     * resolves the task as complete
> +     *  @langversion 3.0
> +     *  @playerversion Flash 10.2
> +     *  @playerversion AIR 2.6
> +     *  @productversion Royale 0.9.6
> +     */
> +    public function complete():void{
> +      _status = "complete";
> +      dispatchEvent(new Event("complete"));
> +      notifyDone();
> +    }
> +    /**
> +     * Resolves the task as failed
> +     *  @langversion 3.0
> +     *  @playerversion Flash 10.2
> +     *  @playerversion AIR 2.6
> +     *  @productversion Royale 0.9.6
> +     */
> +    public function fail():void{
> +      _status = "failed";
> +      dispatchEvent(new Event("failed"));
> +      notifyDone();
> +    }
> +    protected function notifyDone():void{
> +      dispatchEvent(new Event("done"));
> +      if(!doneCallbacks){
> +        return;
> +      }
> +      for(var i:int=0;i<doneCallbacks.length;i++){
> +        doneCallbacks[i](this);
> +      }
> +    }
> +    private var doneCallbacks:Array;
> +
> +    /**
> +     * done accepts a callback which is called when the task is resolved.
> +     * The callback is resolved whether the task is successfully completed or not.
> +     * The properties of the task should be examined in the callback to determine the results.
> +     * The `done` event can be listened too as well.
> +     *  @langversion 3.0
> +     *  @playerversion Flash 10.2
> +     *  @playerversion AIR 2.6
> +     *  @productversion Royale 0.9.6
> +     */
> +    public function done(callback:Function):AsyncTask{
> +      if(!doneCallbacks){
> +        doneCallbacks = [];
> +      }
> +      doneCallbacks.push(callback);
> +      return this;
> +    }
> +    public abstract function run(data:Object=null):void;
> +
> +    /**
> +     * cancel resolves the task as "canceled"
> +     *  @langversion 3.0
> +     *  @playerversion Flash 10.2
> +     *  @playerversion AIR 2.6
> +     *  @productversion Royale 0.9.6
> +     */
> +    public function cancel():void
> +    {
> +      _status = "canceled";
> +      notifyDone();
> +    }
> +
> +    private var _data:Object;
> +    /**
> +     * The data of the task
> +     *  @langversion 3.0
> +     *  @playerversion Flash 10.2
> +     *  @playerversion AIR 2.6
> +     *  @productversion Royale 0.9.6
> +     */
> +    public function get data():Object
> +    {
> +    	return _data;
> +    }
> +
> +    public function set data(value:Object):void
> +    {
> +    	_data = value;
> +    }
> +
> +  }
> +}
> \ No newline at end of file
> diff --git a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/CompoundAsyncTask.as b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/CompoundAsyncTask.as
> new file mode 100644
> index 0000000..3dee5ef
> --- /dev/null
> +++ b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/CompoundAsyncTask.as
> @@ -0,0 +1,135 @@
> +////////////////////////////////////////////////////////////////////////////////
> +//
> +//  Licensed to the Apache Software Foundation (ASF) under one or more
> +//  contributor license agreements.  See the NOTICE file distributed with
> +//  this work for additional information regarding copyright ownership.
> +//  The ASF licenses this file to You under the Apache License, Version 2.0
> +//  (the "License"); you may not use this file except in compliance with
> +//  the License.  You may obtain a copy of the License at
> +//
> +//      http://www.apache.org/licenses/LICENSE-2.0
> +//
> +//  Unless required by applicable law or agreed to in writing, software
> +//  distributed under the License is distributed on an "AS IS" BASIS,
> +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> +//  See the License for the specific language governing permissions and
> +//  limitations under the License.
> +//
> +////////////////////////////////////////////////////////////////////////////////
> +package org.apache.royale.utils.async
> +{
> +  import org.apache.royale.events.Event;
> +
> +  /**
> +   * The CompoundAsyncTask class allows running a number of AsyncTasks in parallel and resolves when they are done.
> +   */
> +  public class CompoundAsyncTask extends AsyncTask
> +  {
> +    public function CompoundAsyncTask(tasks:Array=null)
> +    {
> +      super();
> +      if(!tasks){
> +        tasks = [];
> +      }
> +      this.tasks = tasks;
> +      completedTasks = [];
> +      failedTasks = [];
> +    }
> +    protected var tasks:Array;
> +
> +    private var _failEarly:Boolean;
> +    /**
> +     * If <code>failEarly</code> is true, the task will fail as soon as the first subtask fails.
> +     */
> +    public function get failEarly():Boolean
> +    {
> +    	return _failEarly;
> +    }
> +
> +    public function set failEarly(value:Boolean):void
> +    {
> +    	_failEarly = value;
> +    }
> +
> +    public function addTask(task:AsyncTask):void{
> +      tasks.push(task);
> +    }
> +    
> +    protected var pendingTasks:Array;
> +
> +    /**
> +     *  @royalesuppresspublicvarwarning
> +     */
> +    public var completedTasks:Array;
> +    /**
> +     *  @royalesuppresspublicvarwarning
> +     */
> +    public var failedTasks:Array;
> +
> +    override public function run(data:Object=null):void
> +    {
> +      if(_status == "pending"){// don't allow running twice
> +        return;
> +      }
> +      _status = "pending";
> +      pendingTasks = [];
> +      for(var i:int=0;i<tasks.length;i++){
> +        var task:AsyncTask = tasks[i];
> +        task.done(handleDone);
> +        pendingTasks.push(task);
> +        task.run();
> +      }
> +    }
> +    private function handleDone(task:AsyncTask):void
> +    {
> +      if(_status != "pending")
> +      {
> +        return;
> +      }
> +      var idx:int = pendingTasks.indexOf(task);
> +      pendingTasks.splice(idx,1);
> +      switch(task.status){
> +        case "complete":
> +          completedTasks.push(task);
> +          break;
> +        case "failed":
> +          failedTasks.push(task);
> +          if(failEarly)
> +          {
> +            while(pendingTasks.length)
> +            {
> +              var pending:AsyncTask = pendingTasks.pop();
> +              pending.cancel();
> +            }
> +            fail();
> +            return;
> +          }
> +          break;
> +        default:// not sure why this would happen
> +          throw new Error("Unknown task status");
> +      }
> +      if(pendingTasks.length == 0)
> +      {
> +        setFinalStatus();
> +      }
> +    }
> +    protected function setFinalStatus():void
> +    {
> +      if(failedTasks.length == 0)
> +      {
> +        complete();
> +      }
> +      else if(completedTasks.length == 0)
> +      {
> +        fail();
> +      }
> +      else
> +      {// Some passed and some failed -- Does this make sense?
> +        _status = "mixed";
> +        dispatchEvent(new Event("failed"));
> +        dispatchEvent(new Event("complete"));
> +        notifyDone();
> +      }      
> +    }
> +  }
> +}
> \ No newline at end of file
> diff --git a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/SequentialAsyncTask.as b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/SequentialAsyncTask.as
> new file mode 100644
> index 0000000..77f2f18
> --- /dev/null
> +++ b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/SequentialAsyncTask.as
> @@ -0,0 +1,77 @@
> +////////////////////////////////////////////////////////////////////////////////
> +//
> +//  Licensed to the Apache Software Foundation (ASF) under one or more
> +//  contributor license agreements.  See the NOTICE file distributed with
> +//  this work for additional information regarding copyright ownership.
> +//  The ASF licenses this file to You under the Apache License, Version 2.0
> +//  (the "License"); you may not use this file except in compliance with
> +//  the License.  You may obtain a copy of the License at
> +//
> +//      http://www.apache.org/licenses/LICENSE-2.0
> +//
> +//  Unless required by applicable law or agreed to in writing, software
> +//  distributed under the License is distributed on an "AS IS" BASIS,
> +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> +//  See the License for the specific language governing permissions and
> +//  limitations under the License.
> +//
> +////////////////////////////////////////////////////////////////////////////////
> +package org.apache.royale.utils.async
> +{
> +  /**
> +   * The SequentialAsyncTask runs a list of tasks in sequential order.
> +   * Each sunsequent task is only run once the previous task is done.
> +   * The previous task is used as the argument for the next task's run method.
> +   * This enables the chaining of results.
> +   */
> +  public class SequentialAsyncTask extends CompoundAsyncTask
> +  {
> +    /**
> +     *  @langversion 3.0
> +     *  @playerversion Flash 10.2
> +     *  @playerversion AIR 2.6
> +     *  @productversion Royale 0.9.6
> +     */
> +    public function SequentialAsyncTask(tasks:Array=null)
> +    {
> +      super(tasks);
> +    }
> +    override public function run(data:Object=null):void
> +    {
> +      _status = "pending";
> +      pendingTasks = tasks.slice();
> +      var task:AsyncTask = pendingTasks.shift();
> +      task.done(handleDone);
> +      task.run();
> +    }
> +    private function handleDone(task:AsyncTask):void
> +    {
> +      if(_status != "pending"){
> +        return;
> +      }
> +      switch(task.status){
> +        case "complete":
> +          completedTasks.push(task);
> +          break;
> +        case "failed":
> +          failedTasks.push(task);
> +          if(failEarly){
> +            pendingTasks = [];
> +            fail();
> +            return;
> +          }
> +          break;
> +        default:// not sure why this would happen
> +          throw new Error("Unknown task status");
> +
> +      }
> +      if(pendingTasks.length){
> +        var nextTask:AsyncTask = pendingTasks.shift();
> +        nextTask.done(handleDone);
> +        nextTask.run(task);
> +      } else {
> +        setFinalStatus();
> +      }
> +    }
> +  }
> +}
> \ No newline at end of file
> 


Re: [royale-asjs] branch develop updated: Added Async tasks

Posted by Piotr Zarzycki <pi...@gmail.com>.
Wow that's super awesome! Thanks for this example!

On Tue, Jun 4, 2019, 2:03 PM Harbs <ha...@gmail.com> wrote:

> I finally got fed up enough with Promises et. al. that I broke down and
> wrote some Async classes which (IMO) are much easier to use.
>
> AsyncTask needs to be subclassed. Here’s an implementation that I’m using
> in my app. If I find some time, I might create some HTTP tasks. I someone
> who’s better at docs than me wants to write something, that would be great.
> ;-)
>
> package com.printui.utils
> {
>   import com.printui.model.vos.FontVO;
>   import com.printui.model.proxies.FontProxy;
>
>   public class LoadFontTask extends AsyncTask
>   {
>     public function LoadFontTask(font:FontVO)
>     {
>       super();
>       this.font = font;
>     }
>     private var font:FontVO;
>     override public function run(data:Object = null):void{
>       var fp:FontProxy =
> ApplicationFacade.getInstance().retrieveProxy(FontProxy.NAME) as FontProxy;
>       fp.loadNow(font,fontLoadDone);
>     }
>     private function fontLoadDone():void{
>       if(font.embedded){
>         complete();
>       } else {
>         fail();
>       }
>     }
>   }
> }
>
> I’m using it like so:
>
>     public function embedFonts(callback:Function):void{
>       if(fontsEmbedded()){
>         callback();
>       } else {
>         var tasks:Array = [];
>         var font:FontVO = getAppliedFont();
>         if(!font.embedded){
>           tasks.push(new LoadFontTask(font));
>         }
>         font = getBulletFont();
>         if(font && !font.embedded){
>           tasks.push(new LoadFontTask(font));
>         }
>         var task:CompoundAsyncTask = new CompoundAsyncTask(tasks);
>         task.done(function(task:AsyncTask):void{
>           if(task.status == "complete"){
>             // we're good
>             callback();
>           } else {
>             // status is "failed" -- not sure what to do...
>           }
>         });
>         task.run();
>       }
>     }
>
>
> > On Jun 4, 2019, at 2:55 PM, harbs@apache.org wrote:
> >
> > This is an automated email from the ASF dual-hosted git repository.
> >
> > harbs pushed a commit to branch develop
> > in repository https://gitbox.apache.org/repos/asf/royale-asjs.git
> >
> >
> > The following commit(s) were added to refs/heads/develop by this push:
> >     new edb052c  Added Async tasks
> > edb052c is described below
> >
> > commit edb052cbf2fb1b9db276dff6e4a94ce0a7679f00
> > Author: Harbs <ha...@in-tools.com>
> > AuthorDate: Tue Jun 4 14:55:00 2019 +0300
> >
> >    Added Async tasks
> > ---
> > .../CoreJS/src/main/config/compile-js-config.xml   |   1 +
> > .../Core/src/main/config/compile-swf-config.xml    |   1 +
> > .../Core/src/main/resources/basic-manifest.xml     |   3 +
> > .../projects/Core/src/main/royale/CoreClasses.as   |   3 +
> > .../royale/org/apache/royale/utils/ObjectMap.as    |  12 ++
> > .../org/apache/royale/utils/async/AsyncTask.as     | 180
> +++++++++++++++++++++
> > .../apache/royale/utils/async/CompoundAsyncTask.as | 135 ++++++++++++++++
> > .../royale/utils/async/SequentialAsyncTask.as      |  77 +++++++++
> > 8 files changed, 412 insertions(+)
> >
> > diff --git
> a/frameworks/js/projects/CoreJS/src/main/config/compile-js-config.xml
> b/frameworks/js/projects/CoreJS/src/main/config/compile-js-config.xml
> > index bdc495e..e912e57 100644
> > --- a/frameworks/js/projects/CoreJS/src/main/config/compile-js-config.xml
> > +++ b/frameworks/js/projects/CoreJS/src/main/config/compile-js-config.xml
> > @@ -71,6 +71,7 @@
> >         </source-path>
> >
> >         <warn-no-constructor>false</warn-no-constructor>
> > +        <allow-abstract-classes>true</allow-abstract-classes>
> >
> >         <!-- Use of the instanceof operator. -->
> >         <warn-instance-of-changes>false</warn-instance-of-changes>
> > diff --git
> a/frameworks/projects/Core/src/main/config/compile-swf-config.xml
> b/frameworks/projects/Core/src/main/config/compile-swf-config.xml
> > index ecd4c77..265d4d8 100644
> > --- a/frameworks/projects/Core/src/main/config/compile-swf-config.xml
> > +++ b/frameworks/projects/Core/src/main/config/compile-swf-config.xml
> > @@ -75,6 +75,7 @@
> >         </source-path>
> >
> >         <warn-no-constructor>false</warn-no-constructor>
> > +        <allow-abstract-classes>true</allow-abstract-classes>
> >
> >         <!-- Use of the instanceof operator. -->
> >         <warn-instance-of-changes>false</warn-instance-of-changes>
> > diff --git
> a/frameworks/projects/Core/src/main/resources/basic-manifest.xml
> b/frameworks/projects/Core/src/main/resources/basic-manifest.xml
> > index ae4b7f7..f40d2e4 100644
> > --- a/frameworks/projects/Core/src/main/resources/basic-manifest.xml
> > +++ b/frameworks/projects/Core/src/main/resources/basic-manifest.xml
> > @@ -52,4 +52,7 @@
> >     <component id="StyleChangeNotifier"
> class="org.apache.royale.core.StyleChangeNotifier"/>
> >
> >     <component id="State" class="org.apache.royale.states.State"/>
> > +
> > +    <component id="CompoundAsyncTask"
> class="org.apache.royale.utils.CompoundAsyncTask">
> > +    <component id="SequentialAsyncTask"
> class="org.apache.royale.utils.SequentialAsyncTask">
> > </componentPackage>
> > diff --git a/frameworks/projects/Core/src/main/royale/CoreClasses.as
> b/frameworks/projects/Core/src/main/royale/CoreClasses.as
> > index 678df00..cdd9b25 100644
> > --- a/frameworks/projects/Core/src/main/royale/CoreClasses.as
> > +++ b/frameworks/projects/Core/src/main/royale/CoreClasses.as
> > @@ -308,6 +308,9 @@ internal class CoreClasses
> >       import org.apache.royale.utils.date.addSeconds; addSeconds;
> >       import org.apache.royale.utils.date.addYears; addYears;
> >
> > +     import org.apache.royale.utils.async.CompoundAsyncTask;
> CompoundAsyncTask;
> > +     import org.apache.royale.utils.async.SequentialAsyncTask;
> SequentialAsyncTask;
> > +
> >       import org.apache.royale.utils.css.addDynamicSelector;
> addDynamicSelector;
> >
> >       COMPILE::JS
> > diff --git
> a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/ObjectMap.as
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/ObjectMap.as
> > index d3bd5bc..836b76e 100644
> > ---
> a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/ObjectMap.as
> > +++
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/ObjectMap.as
> > @@ -157,9 +157,21 @@ package org.apache.royale.utils
> >
> >         COMPILE::JS
> >         {
> > +            /**
> > +             *  @royalesuppresspublicvarwarning
> > +             */
> >             public var get:Function = objectGet;
> > +            /**
> > +             *  @royalesuppresspublicvarwarning
> > +             */
> >             public var set:Function = objectSet;
> > +            /**
> > +             *  @royalesuppresspublicvarwarning
> > +             */
> >             public var has:Function = objectHas;
> > +            /**
> > +             *  @royalesuppresspublicvarwarning
> > +             */
> >             public var delete:Function = objectDelete;
> >         }
> >
> > diff --git
> a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/AsyncTask.as
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/AsyncTask.as
> > new file mode 100644
> > index 0000000..44a31ce
> > --- /dev/null
> > +++
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/AsyncTask.as
> > @@ -0,0 +1,180 @@
> >
> +////////////////////////////////////////////////////////////////////////////////
> > +//
> > +//  Licensed to the Apache Software Foundation (ASF) under one or more
> > +//  contributor license agreements.  See the NOTICE file distributed
> with
> > +//  this work for additional information regarding copyright ownership.
> > +//  The ASF licenses this file to You under the Apache License, Version
> 2.0
> > +//  (the "License"); you may not use this file except in compliance with
> > +//  the License.  You may obtain a copy of the License at
> > +//
> > +//      http://www.apache.org/licenses/LICENSE-2.0
> > +//
> > +//  Unless required by applicable law or agreed to in writing, software
> > +//  distributed under the License is distributed on an "AS IS" BASIS,
> > +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> > +//  See the License for the specific language governing permissions and
> > +//  limitations under the License.
> > +//
> >
> +////////////////////////////////////////////////////////////////////////////////
> > +package org.apache.royale.utils.async
> > +{
> > +  import org.apache.royale.events.EventDispatcher;
> > +  import org.apache.royale.events.Event;
> > +
> > +  /**
> > +   * AsyncTask is a base class for AsyncTasks which let the caller know
> when they are done.
> > +   * AsyncTask is an OOP replacement for Promises and simple callbacks
> which allows for
> > +   * strongly typed async requests with any kind of payload and
> behavior.
> > +   * AsyncTask must be subclassed to be used.
> > +   * The subclass must implement the `run` method to define the
> behavior when the task is "run".
> > +   */
> > +
> > +  [Event(name="complete", type="org.apache.royale.events.Event")]
> > +  [Event(name="failed", type="org.apache.royale.events.Event")]
> > +  [Event(name="done", type="org.apache.royale.events.Event")]
> > +  public abstract class AsyncTask extends EventDispatcher
> > +  {
> > +    public function AsyncTask()
> > +    {
> > +
> > +    }
> > +    public static const INITIALIZED:String = "initialized";
> > +    public static const PENDING:String = "pending";
> > +    public static const COMPLETE:String = "complete";
> > +    public static const CANCELED:String = "canceled";
> > +    public static const FAILED:String = "failed";
> > +    /**
> > +     * Used in compound tasks
> > +     */
> > +    public static const MIXED:String = "mixed";
> > +    protected var _status:String = "initialized";
> > +    /**
> > +     * One of: initialized, pending, complete, failed or mixed (for
> compound tasks)
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function get status():String
> > +    {
> > +      return _status;
> > +    }
> > +
> > +    /**
> > +     * completed (and a status of `complete`) means the task completed
> successfully
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function get completed():Boolean
> > +    {
> > +     return _status == "complete";
> > +    }
> > +    public function set completed(value:Boolean):void
> > +    {
> > +     _status = "complete";
> > +    }
> > +
> > +    /**
> > +     * failed (and a status of `failed`) means the task resolved to a
> failed state
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function get failed():Boolean
> > +    {
> > +     return _status == "failed";
> > +    }
> > +    public function set failed(value:Boolean):void
> > +    {
> > +     _status = "failed";
> > +    }
> > +    /**
> > +     * resolves the task as complete
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function complete():void{
> > +      _status = "complete";
> > +      dispatchEvent(new Event("complete"));
> > +      notifyDone();
> > +    }
> > +    /**
> > +     * Resolves the task as failed
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function fail():void{
> > +      _status = "failed";
> > +      dispatchEvent(new Event("failed"));
> > +      notifyDone();
> > +    }
> > +    protected function notifyDone():void{
> > +      dispatchEvent(new Event("done"));
> > +      if(!doneCallbacks){
> > +        return;
> > +      }
> > +      for(var i:int=0;i<doneCallbacks.length;i++){
> > +        doneCallbacks[i](this);
> > +      }
> > +    }
> > +    private var doneCallbacks:Array;
> > +
> > +    /**
> > +     * done accepts a callback which is called when the task is
> resolved.
> > +     * The callback is resolved whether the task is successfully
> completed or not.
> > +     * The properties of the task should be examined in the callback to
> determine the results.
> > +     * The `done` event can be listened too as well.
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function done(callback:Function):AsyncTask{
> > +      if(!doneCallbacks){
> > +        doneCallbacks = [];
> > +      }
> > +      doneCallbacks.push(callback);
> > +      return this;
> > +    }
> > +    public abstract function run(data:Object=null):void;
> > +
> > +    /**
> > +     * cancel resolves the task as "canceled"
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function cancel():void
> > +    {
> > +      _status = "canceled";
> > +      notifyDone();
> > +    }
> > +
> > +    private var _data:Object;
> > +    /**
> > +     * The data of the task
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function get data():Object
> > +    {
> > +     return _data;
> > +    }
> > +
> > +    public function set data(value:Object):void
> > +    {
> > +     _data = value;
> > +    }
> > +
> > +  }
> > +}
> > \ No newline at end of file
> > diff --git
> a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/CompoundAsyncTask.as
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/CompoundAsyncTask.as
> > new file mode 100644
> > index 0000000..3dee5ef
> > --- /dev/null
> > +++
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/CompoundAsyncTask.as
> > @@ -0,0 +1,135 @@
> >
> +////////////////////////////////////////////////////////////////////////////////
> > +//
> > +//  Licensed to the Apache Software Foundation (ASF) under one or more
> > +//  contributor license agreements.  See the NOTICE file distributed
> with
> > +//  this work for additional information regarding copyright ownership.
> > +//  The ASF licenses this file to You under the Apache License, Version
> 2.0
> > +//  (the "License"); you may not use this file except in compliance with
> > +//  the License.  You may obtain a copy of the License at
> > +//
> > +//      http://www.apache.org/licenses/LICENSE-2.0
> > +//
> > +//  Unless required by applicable law or agreed to in writing, software
> > +//  distributed under the License is distributed on an "AS IS" BASIS,
> > +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> > +//  See the License for the specific language governing permissions and
> > +//  limitations under the License.
> > +//
> >
> +////////////////////////////////////////////////////////////////////////////////
> > +package org.apache.royale.utils.async
> > +{
> > +  import org.apache.royale.events.Event;
> > +
> > +  /**
> > +   * The CompoundAsyncTask class allows running a number of AsyncTasks
> in parallel and resolves when they are done.
> > +   */
> > +  public class CompoundAsyncTask extends AsyncTask
> > +  {
> > +    public function CompoundAsyncTask(tasks:Array=null)
> > +    {
> > +      super();
> > +      if(!tasks){
> > +        tasks = [];
> > +      }
> > +      this.tasks = tasks;
> > +      completedTasks = [];
> > +      failedTasks = [];
> > +    }
> > +    protected var tasks:Array;
> > +
> > +    private var _failEarly:Boolean;
> > +    /**
> > +     * If <code>failEarly</code> is true, the task will fail as soon as
> the first subtask fails.
> > +     */
> > +    public function get failEarly():Boolean
> > +    {
> > +     return _failEarly;
> > +    }
> > +
> > +    public function set failEarly(value:Boolean):void
> > +    {
> > +     _failEarly = value;
> > +    }
> > +
> > +    public function addTask(task:AsyncTask):void{
> > +      tasks.push(task);
> > +    }
> > +
> > +    protected var pendingTasks:Array;
> > +
> > +    /**
> > +     *  @royalesuppresspublicvarwarning
> > +     */
> > +    public var completedTasks:Array;
> > +    /**
> > +     *  @royalesuppresspublicvarwarning
> > +     */
> > +    public var failedTasks:Array;
> > +
> > +    override public function run(data:Object=null):void
> > +    {
> > +      if(_status == "pending"){// don't allow running twice
> > +        return;
> > +      }
> > +      _status = "pending";
> > +      pendingTasks = [];
> > +      for(var i:int=0;i<tasks.length;i++){
> > +        var task:AsyncTask = tasks[i];
> > +        task.done(handleDone);
> > +        pendingTasks.push(task);
> > +        task.run();
> > +      }
> > +    }
> > +    private function handleDone(task:AsyncTask):void
> > +    {
> > +      if(_status != "pending")
> > +      {
> > +        return;
> > +      }
> > +      var idx:int = pendingTasks.indexOf(task);
> > +      pendingTasks.splice(idx,1);
> > +      switch(task.status){
> > +        case "complete":
> > +          completedTasks.push(task);
> > +          break;
> > +        case "failed":
> > +          failedTasks.push(task);
> > +          if(failEarly)
> > +          {
> > +            while(pendingTasks.length)
> > +            {
> > +              var pending:AsyncTask = pendingTasks.pop();
> > +              pending.cancel();
> > +            }
> > +            fail();
> > +            return;
> > +          }
> > +          break;
> > +        default:// not sure why this would happen
> > +          throw new Error("Unknown task status");
> > +      }
> > +      if(pendingTasks.length == 0)
> > +      {
> > +        setFinalStatus();
> > +      }
> > +    }
> > +    protected function setFinalStatus():void
> > +    {
> > +      if(failedTasks.length == 0)
> > +      {
> > +        complete();
> > +      }
> > +      else if(completedTasks.length == 0)
> > +      {
> > +        fail();
> > +      }
> > +      else
> > +      {// Some passed and some failed -- Does this make sense?
> > +        _status = "mixed";
> > +        dispatchEvent(new Event("failed"));
> > +        dispatchEvent(new Event("complete"));
> > +        notifyDone();
> > +      }
> > +    }
> > +  }
> > +}
> > \ No newline at end of file
> > diff --git
> a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/SequentialAsyncTask.as
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/SequentialAsyncTask.as
> > new file mode 100644
> > index 0000000..77f2f18
> > --- /dev/null
> > +++
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/SequentialAsyncTask.as
> > @@ -0,0 +1,77 @@
> >
> +////////////////////////////////////////////////////////////////////////////////
> > +//
> > +//  Licensed to the Apache Software Foundation (ASF) under one or more
> > +//  contributor license agreements.  See the NOTICE file distributed
> with
> > +//  this work for additional information regarding copyright ownership.
> > +//  The ASF licenses this file to You under the Apache License, Version
> 2.0
> > +//  (the "License"); you may not use this file except in compliance with
> > +//  the License.  You may obtain a copy of the License at
> > +//
> > +//      http://www.apache.org/licenses/LICENSE-2.0
> > +//
> > +//  Unless required by applicable law or agreed to in writing, software
> > +//  distributed under the License is distributed on an "AS IS" BASIS,
> > +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> > +//  See the License for the specific language governing permissions and
> > +//  limitations under the License.
> > +//
> >
> +////////////////////////////////////////////////////////////////////////////////
> > +package org.apache.royale.utils.async
> > +{
> > +  /**
> > +   * The SequentialAsyncTask runs a list of tasks in sequential order.
> > +   * Each sunsequent task is only run once the previous task is done.
> > +   * The previous task is used as the argument for the next task's run
> method.
> > +   * This enables the chaining of results.
> > +   */
> > +  public class SequentialAsyncTask extends CompoundAsyncTask
> > +  {
> > +    /**
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function SequentialAsyncTask(tasks:Array=null)
> > +    {
> > +      super(tasks);
> > +    }
> > +    override public function run(data:Object=null):void
> > +    {
> > +      _status = "pending";
> > +      pendingTasks = tasks.slice();
> > +      var task:AsyncTask = pendingTasks.shift();
> > +      task.done(handleDone);
> > +      task.run();
> > +    }
> > +    private function handleDone(task:AsyncTask):void
> > +    {
> > +      if(_status != "pending"){
> > +        return;
> > +      }
> > +      switch(task.status){
> > +        case "complete":
> > +          completedTasks.push(task);
> > +          break;
> > +        case "failed":
> > +          failedTasks.push(task);
> > +          if(failEarly){
> > +            pendingTasks = [];
> > +            fail();
> > +            return;
> > +          }
> > +          break;
> > +        default:// not sure why this would happen
> > +          throw new Error("Unknown task status");
> > +
> > +      }
> > +      if(pendingTasks.length){
> > +        var nextTask:AsyncTask = pendingTasks.shift();
> > +        nextTask.done(handleDone);
> > +        nextTask.run(task);
> > +      } else {
> > +        setFinalStatus();
> > +      }
> > +    }
> > +  }
> > +}
> > \ No newline at end of file
> >
>
>

Re: [royale-asjs] branch develop updated: Added Async tasks

Posted by Carlos Rovira <ca...@apache.org>.
Hi Harbs,

any of us that are working on Docs now can do this, but I think we need
more explanation about what is all about.
Is important to create a code that works, but is equally important to
explain what is the purpose so we can understand what's the improvement.
And I think this goes for all of us, included me.

Can you explain more about this?
As well give some clues of where s that code located, seems in print, but
nor in Royale?

With all of that then we can plan some docs to expose this.

Thanks! :)

El mar., 4 jun. 2019 a las 14:03, Harbs (<ha...@gmail.com>) escribió:

> I finally got fed up enough with Promises et. al. that I broke down and
> wrote some Async classes which (IMO) are much easier to use.
>
> AsyncTask needs to be subclassed. Here’s an implementation that I’m using
> in my app. If I find some time, I might create some HTTP tasks. I someone
> who’s better at docs than me wants to write something, that would be great.
> ;-)
>
> package com.printui.utils
> {
>   import com.printui.model.vos.FontVO;
>   import com.printui.model.proxies.FontProxy;
>
>   public class LoadFontTask extends AsyncTask
>   {
>     public function LoadFontTask(font:FontVO)
>     {
>       super();
>       this.font = font;
>     }
>     private var font:FontVO;
>     override public function run(data:Object = null):void{
>       var fp:FontProxy =
> ApplicationFacade.getInstance().retrieveProxy(FontProxy.NAME) as FontProxy;
>       fp.loadNow(font,fontLoadDone);
>     }
>     private function fontLoadDone():void{
>       if(font.embedded){
>         complete();
>       } else {
>         fail();
>       }
>     }
>   }
> }
>
> I’m using it like so:
>
>     public function embedFonts(callback:Function):void{
>       if(fontsEmbedded()){
>         callback();
>       } else {
>         var tasks:Array = [];
>         var font:FontVO = getAppliedFont();
>         if(!font.embedded){
>           tasks.push(new LoadFontTask(font));
>         }
>         font = getBulletFont();
>         if(font && !font.embedded){
>           tasks.push(new LoadFontTask(font));
>         }
>         var task:CompoundAsyncTask = new CompoundAsyncTask(tasks);
>         task.done(function(task:AsyncTask):void{
>           if(task.status == "complete"){
>             // we're good
>             callback();
>           } else {
>             // status is "failed" -- not sure what to do...
>           }
>         });
>         task.run();
>       }
>     }
>
>
> > On Jun 4, 2019, at 2:55 PM, harbs@apache.org wrote:
> >
> > This is an automated email from the ASF dual-hosted git repository.
> >
> > harbs pushed a commit to branch develop
> > in repository https://gitbox.apache.org/repos/asf/royale-asjs.git
> >
> >
> > The following commit(s) were added to refs/heads/develop by this push:
> >     new edb052c  Added Async tasks
> > edb052c is described below
> >
> > commit edb052cbf2fb1b9db276dff6e4a94ce0a7679f00
> > Author: Harbs <ha...@in-tools.com>
> > AuthorDate: Tue Jun 4 14:55:00 2019 +0300
> >
> >    Added Async tasks
> > ---
> > .../CoreJS/src/main/config/compile-js-config.xml   |   1 +
> > .../Core/src/main/config/compile-swf-config.xml    |   1 +
> > .../Core/src/main/resources/basic-manifest.xml     |   3 +
> > .../projects/Core/src/main/royale/CoreClasses.as   |   3 +
> > .../royale/org/apache/royale/utils/ObjectMap.as    |  12 ++
> > .../org/apache/royale/utils/async/AsyncTask.as     | 180
> +++++++++++++++++++++
> > .../apache/royale/utils/async/CompoundAsyncTask.as | 135 ++++++++++++++++
> > .../royale/utils/async/SequentialAsyncTask.as      |  77 +++++++++
> > 8 files changed, 412 insertions(+)
> >
> > diff --git
> a/frameworks/js/projects/CoreJS/src/main/config/compile-js-config.xml
> b/frameworks/js/projects/CoreJS/src/main/config/compile-js-config.xml
> > index bdc495e..e912e57 100644
> > --- a/frameworks/js/projects/CoreJS/src/main/config/compile-js-config.xml
> > +++ b/frameworks/js/projects/CoreJS/src/main/config/compile-js-config.xml
> > @@ -71,6 +71,7 @@
> >         </source-path>
> >
> >         <warn-no-constructor>false</warn-no-constructor>
> > +        <allow-abstract-classes>true</allow-abstract-classes>
> >
> >         <!-- Use of the instanceof operator. -->
> >         <warn-instance-of-changes>false</warn-instance-of-changes>
> > diff --git
> a/frameworks/projects/Core/src/main/config/compile-swf-config.xml
> b/frameworks/projects/Core/src/main/config/compile-swf-config.xml
> > index ecd4c77..265d4d8 100644
> > --- a/frameworks/projects/Core/src/main/config/compile-swf-config.xml
> > +++ b/frameworks/projects/Core/src/main/config/compile-swf-config.xml
> > @@ -75,6 +75,7 @@
> >         </source-path>
> >
> >         <warn-no-constructor>false</warn-no-constructor>
> > +        <allow-abstract-classes>true</allow-abstract-classes>
> >
> >         <!-- Use of the instanceof operator. -->
> >         <warn-instance-of-changes>false</warn-instance-of-changes>
> > diff --git
> a/frameworks/projects/Core/src/main/resources/basic-manifest.xml
> b/frameworks/projects/Core/src/main/resources/basic-manifest.xml
> > index ae4b7f7..f40d2e4 100644
> > --- a/frameworks/projects/Core/src/main/resources/basic-manifest.xml
> > +++ b/frameworks/projects/Core/src/main/resources/basic-manifest.xml
> > @@ -52,4 +52,7 @@
> >     <component id="StyleChangeNotifier"
> class="org.apache.royale.core.StyleChangeNotifier"/>
> >
> >     <component id="State" class="org.apache.royale.states.State"/>
> > +
> > +    <component id="CompoundAsyncTask"
> class="org.apache.royale.utils.CompoundAsyncTask">
> > +    <component id="SequentialAsyncTask"
> class="org.apache.royale.utils.SequentialAsyncTask">
> > </componentPackage>
> > diff --git a/frameworks/projects/Core/src/main/royale/CoreClasses.as
> b/frameworks/projects/Core/src/main/royale/CoreClasses.as
> > index 678df00..cdd9b25 100644
> > --- a/frameworks/projects/Core/src/main/royale/CoreClasses.as
> > +++ b/frameworks/projects/Core/src/main/royale/CoreClasses.as
> > @@ -308,6 +308,9 @@ internal class CoreClasses
> >       import org.apache.royale.utils.date.addSeconds; addSeconds;
> >       import org.apache.royale.utils.date.addYears; addYears;
> >
> > +     import org.apache.royale.utils.async.CompoundAsyncTask;
> CompoundAsyncTask;
> > +     import org.apache.royale.utils.async.SequentialAsyncTask;
> SequentialAsyncTask;
> > +
> >       import org.apache.royale.utils.css.addDynamicSelector;
> addDynamicSelector;
> >
> >       COMPILE::JS
> > diff --git
> a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/ObjectMap.as
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/ObjectMap.as
> > index d3bd5bc..836b76e 100644
> > ---
> a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/ObjectMap.as
> > +++
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/ObjectMap.as
> > @@ -157,9 +157,21 @@ package org.apache.royale.utils
> >
> >         COMPILE::JS
> >         {
> > +            /**
> > +             *  @royalesuppresspublicvarwarning
> > +             */
> >             public var get:Function = objectGet;
> > +            /**
> > +             *  @royalesuppresspublicvarwarning
> > +             */
> >             public var set:Function = objectSet;
> > +            /**
> > +             *  @royalesuppresspublicvarwarning
> > +             */
> >             public var has:Function = objectHas;
> > +            /**
> > +             *  @royalesuppresspublicvarwarning
> > +             */
> >             public var delete:Function = objectDelete;
> >         }
> >
> > diff --git
> a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/AsyncTask.as
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/AsyncTask.as
> > new file mode 100644
> > index 0000000..44a31ce
> > --- /dev/null
> > +++
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/AsyncTask.as
> > @@ -0,0 +1,180 @@
> >
> +////////////////////////////////////////////////////////////////////////////////
> > +//
> > +//  Licensed to the Apache Software Foundation (ASF) under one or more
> > +//  contributor license agreements.  See the NOTICE file distributed
> with
> > +//  this work for additional information regarding copyright ownership.
> > +//  The ASF licenses this file to You under the Apache License, Version
> 2.0
> > +//  (the "License"); you may not use this file except in compliance with
> > +//  the License.  You may obtain a copy of the License at
> > +//
> > +//      http://www.apache.org/licenses/LICENSE-2.0
> > +//
> > +//  Unless required by applicable law or agreed to in writing, software
> > +//  distributed under the License is distributed on an "AS IS" BASIS,
> > +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> > +//  See the License for the specific language governing permissions and
> > +//  limitations under the License.
> > +//
> >
> +////////////////////////////////////////////////////////////////////////////////
> > +package org.apache.royale.utils.async
> > +{
> > +  import org.apache.royale.events.EventDispatcher;
> > +  import org.apache.royale.events.Event;
> > +
> > +  /**
> > +   * AsyncTask is a base class for AsyncTasks which let the caller know
> when they are done.
> > +   * AsyncTask is an OOP replacement for Promises and simple callbacks
> which allows for
> > +   * strongly typed async requests with any kind of payload and
> behavior.
> > +   * AsyncTask must be subclassed to be used.
> > +   * The subclass must implement the `run` method to define the
> behavior when the task is "run".
> > +   */
> > +
> > +  [Event(name="complete", type="org.apache.royale.events.Event")]
> > +  [Event(name="failed", type="org.apache.royale.events.Event")]
> > +  [Event(name="done", type="org.apache.royale.events.Event")]
> > +  public abstract class AsyncTask extends EventDispatcher
> > +  {
> > +    public function AsyncTask()
> > +    {
> > +
> > +    }
> > +    public static const INITIALIZED:String = "initialized";
> > +    public static const PENDING:String = "pending";
> > +    public static const COMPLETE:String = "complete";
> > +    public static const CANCELED:String = "canceled";
> > +    public static const FAILED:String = "failed";
> > +    /**
> > +     * Used in compound tasks
> > +     */
> > +    public static const MIXED:String = "mixed";
> > +    protected var _status:String = "initialized";
> > +    /**
> > +     * One of: initialized, pending, complete, failed or mixed (for
> compound tasks)
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function get status():String
> > +    {
> > +      return _status;
> > +    }
> > +
> > +    /**
> > +     * completed (and a status of `complete`) means the task completed
> successfully
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function get completed():Boolean
> > +    {
> > +     return _status == "complete";
> > +    }
> > +    public function set completed(value:Boolean):void
> > +    {
> > +     _status = "complete";
> > +    }
> > +
> > +    /**
> > +     * failed (and a status of `failed`) means the task resolved to a
> failed state
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function get failed():Boolean
> > +    {
> > +     return _status == "failed";
> > +    }
> > +    public function set failed(value:Boolean):void
> > +    {
> > +     _status = "failed";
> > +    }
> > +    /**
> > +     * resolves the task as complete
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function complete():void{
> > +      _status = "complete";
> > +      dispatchEvent(new Event("complete"));
> > +      notifyDone();
> > +    }
> > +    /**
> > +     * Resolves the task as failed
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function fail():void{
> > +      _status = "failed";
> > +      dispatchEvent(new Event("failed"));
> > +      notifyDone();
> > +    }
> > +    protected function notifyDone():void{
> > +      dispatchEvent(new Event("done"));
> > +      if(!doneCallbacks){
> > +        return;
> > +      }
> > +      for(var i:int=0;i<doneCallbacks.length;i++){
> > +        doneCallbacks[i](this);
> > +      }
> > +    }
> > +    private var doneCallbacks:Array;
> > +
> > +    /**
> > +     * done accepts a callback which is called when the task is
> resolved.
> > +     * The callback is resolved whether the task is successfully
> completed or not.
> > +     * The properties of the task should be examined in the callback to
> determine the results.
> > +     * The `done` event can be listened too as well.
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function done(callback:Function):AsyncTask{
> > +      if(!doneCallbacks){
> > +        doneCallbacks = [];
> > +      }
> > +      doneCallbacks.push(callback);
> > +      return this;
> > +    }
> > +    public abstract function run(data:Object=null):void;
> > +
> > +    /**
> > +     * cancel resolves the task as "canceled"
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function cancel():void
> > +    {
> > +      _status = "canceled";
> > +      notifyDone();
> > +    }
> > +
> > +    private var _data:Object;
> > +    /**
> > +     * The data of the task
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function get data():Object
> > +    {
> > +     return _data;
> > +    }
> > +
> > +    public function set data(value:Object):void
> > +    {
> > +     _data = value;
> > +    }
> > +
> > +  }
> > +}
> > \ No newline at end of file
> > diff --git
> a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/CompoundAsyncTask.as
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/CompoundAsyncTask.as
> > new file mode 100644
> > index 0000000..3dee5ef
> > --- /dev/null
> > +++
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/CompoundAsyncTask.as
> > @@ -0,0 +1,135 @@
> >
> +////////////////////////////////////////////////////////////////////////////////
> > +//
> > +//  Licensed to the Apache Software Foundation (ASF) under one or more
> > +//  contributor license agreements.  See the NOTICE file distributed
> with
> > +//  this work for additional information regarding copyright ownership.
> > +//  The ASF licenses this file to You under the Apache License, Version
> 2.0
> > +//  (the "License"); you may not use this file except in compliance with
> > +//  the License.  You may obtain a copy of the License at
> > +//
> > +//      http://www.apache.org/licenses/LICENSE-2.0
> > +//
> > +//  Unless required by applicable law or agreed to in writing, software
> > +//  distributed under the License is distributed on an "AS IS" BASIS,
> > +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> > +//  See the License for the specific language governing permissions and
> > +//  limitations under the License.
> > +//
> >
> +////////////////////////////////////////////////////////////////////////////////
> > +package org.apache.royale.utils.async
> > +{
> > +  import org.apache.royale.events.Event;
> > +
> > +  /**
> > +   * The CompoundAsyncTask class allows running a number of AsyncTasks
> in parallel and resolves when they are done.
> > +   */
> > +  public class CompoundAsyncTask extends AsyncTask
> > +  {
> > +    public function CompoundAsyncTask(tasks:Array=null)
> > +    {
> > +      super();
> > +      if(!tasks){
> > +        tasks = [];
> > +      }
> > +      this.tasks = tasks;
> > +      completedTasks = [];
> > +      failedTasks = [];
> > +    }
> > +    protected var tasks:Array;
> > +
> > +    private var _failEarly:Boolean;
> > +    /**
> > +     * If <code>failEarly</code> is true, the task will fail as soon as
> the first subtask fails.
> > +     */
> > +    public function get failEarly():Boolean
> > +    {
> > +     return _failEarly;
> > +    }
> > +
> > +    public function set failEarly(value:Boolean):void
> > +    {
> > +     _failEarly = value;
> > +    }
> > +
> > +    public function addTask(task:AsyncTask):void{
> > +      tasks.push(task);
> > +    }
> > +
> > +    protected var pendingTasks:Array;
> > +
> > +    /**
> > +     *  @royalesuppresspublicvarwarning
> > +     */
> > +    public var completedTasks:Array;
> > +    /**
> > +     *  @royalesuppresspublicvarwarning
> > +     */
> > +    public var failedTasks:Array;
> > +
> > +    override public function run(data:Object=null):void
> > +    {
> > +      if(_status == "pending"){// don't allow running twice
> > +        return;
> > +      }
> > +      _status = "pending";
> > +      pendingTasks = [];
> > +      for(var i:int=0;i<tasks.length;i++){
> > +        var task:AsyncTask = tasks[i];
> > +        task.done(handleDone);
> > +        pendingTasks.push(task);
> > +        task.run();
> > +      }
> > +    }
> > +    private function handleDone(task:AsyncTask):void
> > +    {
> > +      if(_status != "pending")
> > +      {
> > +        return;
> > +      }
> > +      var idx:int = pendingTasks.indexOf(task);
> > +      pendingTasks.splice(idx,1);
> > +      switch(task.status){
> > +        case "complete":
> > +          completedTasks.push(task);
> > +          break;
> > +        case "failed":
> > +          failedTasks.push(task);
> > +          if(failEarly)
> > +          {
> > +            while(pendingTasks.length)
> > +            {
> > +              var pending:AsyncTask = pendingTasks.pop();
> > +              pending.cancel();
> > +            }
> > +            fail();
> > +            return;
> > +          }
> > +          break;
> > +        default:// not sure why this would happen
> > +          throw new Error("Unknown task status");
> > +      }
> > +      if(pendingTasks.length == 0)
> > +      {
> > +        setFinalStatus();
> > +      }
> > +    }
> > +    protected function setFinalStatus():void
> > +    {
> > +      if(failedTasks.length == 0)
> > +      {
> > +        complete();
> > +      }
> > +      else if(completedTasks.length == 0)
> > +      {
> > +        fail();
> > +      }
> > +      else
> > +      {// Some passed and some failed -- Does this make sense?
> > +        _status = "mixed";
> > +        dispatchEvent(new Event("failed"));
> > +        dispatchEvent(new Event("complete"));
> > +        notifyDone();
> > +      }
> > +    }
> > +  }
> > +}
> > \ No newline at end of file
> > diff --git
> a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/SequentialAsyncTask.as
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/SequentialAsyncTask.as
> > new file mode 100644
> > index 0000000..77f2f18
> > --- /dev/null
> > +++
> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/async/SequentialAsyncTask.as
> > @@ -0,0 +1,77 @@
> >
> +////////////////////////////////////////////////////////////////////////////////
> > +//
> > +//  Licensed to the Apache Software Foundation (ASF) under one or more
> > +//  contributor license agreements.  See the NOTICE file distributed
> with
> > +//  this work for additional information regarding copyright ownership.
> > +//  The ASF licenses this file to You under the Apache License, Version
> 2.0
> > +//  (the "License"); you may not use this file except in compliance with
> > +//  the License.  You may obtain a copy of the License at
> > +//
> > +//      http://www.apache.org/licenses/LICENSE-2.0
> > +//
> > +//  Unless required by applicable law or agreed to in writing, software
> > +//  distributed under the License is distributed on an "AS IS" BASIS,
> > +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> > +//  See the License for the specific language governing permissions and
> > +//  limitations under the License.
> > +//
> >
> +////////////////////////////////////////////////////////////////////////////////
> > +package org.apache.royale.utils.async
> > +{
> > +  /**
> > +   * The SequentialAsyncTask runs a list of tasks in sequential order.
> > +   * Each sunsequent task is only run once the previous task is done.
> > +   * The previous task is used as the argument for the next task's run
> method.
> > +   * This enables the chaining of results.
> > +   */
> > +  public class SequentialAsyncTask extends CompoundAsyncTask
> > +  {
> > +    /**
> > +     *  @langversion 3.0
> > +     *  @playerversion Flash 10.2
> > +     *  @playerversion AIR 2.6
> > +     *  @productversion Royale 0.9.6
> > +     */
> > +    public function SequentialAsyncTask(tasks:Array=null)
> > +    {
> > +      super(tasks);
> > +    }
> > +    override public function run(data:Object=null):void
> > +    {
> > +      _status = "pending";
> > +      pendingTasks = tasks.slice();
> > +      var task:AsyncTask = pendingTasks.shift();
> > +      task.done(handleDone);
> > +      task.run();
> > +    }
> > +    private function handleDone(task:AsyncTask):void
> > +    {
> > +      if(_status != "pending"){
> > +        return;
> > +      }
> > +      switch(task.status){
> > +        case "complete":
> > +          completedTasks.push(task);
> > +          break;
> > +        case "failed":
> > +          failedTasks.push(task);
> > +          if(failEarly){
> > +            pendingTasks = [];
> > +            fail();
> > +            return;
> > +          }
> > +          break;
> > +        default:// not sure why this would happen
> > +          throw new Error("Unknown task status");
> > +
> > +      }
> > +      if(pendingTasks.length){
> > +        var nextTask:AsyncTask = pendingTasks.shift();
> > +        nextTask.done(handleDone);
> > +        nextTask.run(task);
> > +      } else {
> > +        setFinalStatus();
> > +      }
> > +    }
> > +  }
> > +}
> > \ No newline at end of file
> >
>
>

-- 
Carlos Rovira
http://about.me/carlosrovira