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, ha...@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
> 

Reply via email to