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 2021/10/24 10:26:48 UTC

AsyncTasks

I just made a commit and I want to give some background:

I personally strongly dislike Promises. Promises address a need (namely callback hell), but IMO address it poorly. I find Promises unintuitive and difficult to use especially when the use case is complex. I have cases where I have a literally a chain of 35 “then” calls with various catches mixed in. It’s a nightmare to maintain.

Here’s my beefs with Promises
1. You never actually invoke them. You declare a new Promise (or it gets spawned for you) and it magically happens on its own. I hate magic.
2. The aforementioned problem makes it very difficult to control *when* the promise gets invoked.
3. It’s not very intuitive how/when to resolve and reject promises.
4. Promises lend themselves to nested function calls which I find very hard to read.
5. Running many promises and actually dealing with the results is hard and cumbersome.
6. Promise.all can help with the above, but what happens if *some* of them pass? There’s many different ways that you might want to handle that.
7. There’s very little control of parallel vs serial running of promises.
8. What is the result? Hard to know. I’d really like some strongly typed values to make my life easier.
9. How do you deal with progress and promises? It only resolves or rejects. AFAIK, fetch has no way to get progress. How dumb is that?

On top of all this, I just find I always need to go back to the spec every time I use promises. I find them *very* unintuitive.

So I decided to do something about it. My solution is AsyncTasks.

I created AsyncTasks over two years ago and I’ve been using them in my app since then. (My use case was pretty specific to my needs.) I had on my to-do list to add some concrete AsyncTasks to Royale for this whole time and I was finally inspired to follow through…

I just created three Async classes in Network for HTTP requests and I figured now was the time to explain how to use them. ;-)

Basically:
var task: HttpRequestTask = new HttpRequestTask();
task.url = “https://foobaz.com/myapi <https://foobaz.com/myapi>”;
task.done(function(taskReturned:HttpRequestTask):void{
	trace(“task is the same and taskReturned: “ + task == taskReturned);// you get the task back in the done callback
	if(task.status == AsyncTask.COMPLETE){
		trace(task.httpResult);
		trace(task.httpStatus);
	} else {// it failed you can get the status to know why
		trace(task.httpStatus);
        }
});
// you need to run it or nothing happens...
task.run();

That’s a single task. You can also pass an array of tasks (of all types) into a CompoundAsyncTask or a SequentialAsyncTask.

CompoundAsyncTasks run all the requests in parallel. You can failEarly if you want it to complete when the first one errors. Otherwise you have the list of all the tasks when it’s done and you can loop through them to do whatever you want with the results. You can also get the completed and failed tasks separately.

SequentialAsyncTask is the same, but it runs each task when the previous one finished. It passes the previous task into the next one’s run method so you can chain results.

I added tasks for upload and download progress.

I’d like to create one for multipart and File upload as well, but not today…

IMO this architecture addresses every one of my pet peeves. I find them easy to use and reason about. I also just updated them to make it pretty difficult to create memory leaks while using them. 

I hope you like it as much as me… ;-)

Harbs

Re: AsyncTasks

Posted by Edward Stangler <es...@bradmark.com>.
Yeah, Observables have a bit of magic.  And most of rxjs is a bit much,
sometimes.

The equivalent of your example (JS only), in Observables in Angular, for
example, would be:


var sub:Subscription = httpclient.get("https://foobaz.com/myapi",
{responseType: 'text'})
    .subscribe( results => done(results), error => fault(error) );
...
sub.unsubscribe();


And done() and fault() can be anonymous functions (and the "sub"
variable is optional).  And you can cancel and do a few other things.

BehaviorSubject is also nice, in that it lets you have more control over
things.

Not a task system, obviously.



On 10/24/2021 11:46 PM, Harbs wrote:
> async/await makes things both better and worse. It lends itself to less spaghetti code at the price of more magic. The chaining problems still exist with async/await AFAIK.
>
> I conceptually like the idea of Observables, but it’s quite a world of its own. It has a pretty large learning curve and is overkill for any use case I’ve personally had.
>
> AsyncTasks is much less ambitious. It aims to do one thing well rather than tackling every problem in the Async space with one solution that has lots of conventions.
>
> Also, Observables is firmly on the FP train, which I’m not. I prefer OOP solutions to functional ones.
>
> For those not familiar with Observables and how complex/complete (depending on your perspective) it is, take a look at this: https://rxjs.dev/operator-decision-tree
>
> FWIW, I’ve entertained the idea of creating an Observable implementation for Royale, but it was too much for me to undertake considering the chances of me wanting to use it personally is slim.
>
>> On Oct 25, 2021, at 3:15 AM, Edward Stangler wrote:
>>
>>
>> I assume you're describing Promises without async / await, below.
>>
>> How does your stuff compare to Observables?
>>
>>
>>
>> On 10/24/2021 5:28 AM, Harbs wrote:
>>> I just made a commit and I want to give some background:
>>>
>>> I personally strongly dislike Promises. Promises address a need (namely callback hell), but IMO address it poorly. I find Promises unintuitive and difficult to use especially when the use case is complex. I have cases where I have a literally a chain of 35 “then” calls with various catches mixed in. It’s a nightmare to maintain.
>>>
>>> Here’s my beefs with Promises
>>> 1. You never actually invoke them. You declare a new Promise (or it gets spawned for you) and it magically happens on its own. I hate magic.
>>> 2. The aforementioned problem makes it very difficult to control *when* the promise gets invoked.
>>> 3. It’s not very intuitive how/when to resolve and reject promises.
>>> 4. Promises lend themselves to nested function calls which I find very hard to read.
>>> 5. Running many promises and actually dealing with the results is hard and cumbersome.
>>> 6. Promise.all can help with the above, but what happens if *some* of them pass? There’s many different ways that you might want to handle that.
>>> 7. There’s very little control of parallel vs serial running of promises.
>>> 8. What is the result? Hard to know. I’d really like some strongly typed values to make my life easier.
>>> 9. How do you deal with progress and promises? It only resolves or rejects. AFAIK, fetch has no way to get progress. How dumb is that?
>>>
>>> On top of all this, I just find I always need to go back to the spec every time I use promises. I find them *very* unintuitive.
>>>
>>> So I decided to do something about it. My solution is AsyncTasks.
>>>
>>> I created AsyncTasks over two years ago and I’ve been using them in my app since then. (My use case was pretty specific to my needs.) I had on my to-do list to add some concrete AsyncTasks to Royale for this whole time and I was finally inspired to follow through…
>>>
>>> I just created three Async classes in Network for HTTP requests and I figured now was the time to explain how to use them. ;-)
>>>
>>> Basically:
>>> var task: HttpRequestTask = new HttpRequestTask();
>>> task.url = “https://foobaz.com/myapi <https://foobaz.com/myapi> <https://foobaz.com/myapi <https://foobaz.com/myapi>>”;
>>> task.done(function(taskReturned:HttpRequestTask):void{
>>> 	trace(“task is the same and taskReturned: “ + task == taskReturned);// you get the task back in the done callback
>>> 	if(task.status == AsyncTask.COMPLETE){
>>> 		trace(task.httpResult);
>>> 		trace(task.httpStatus);
>>> 	} else {// it failed you can get the status to know why
>>> 		trace(task.httpStatus);
>>>        }
>>> });
>>> // you need to run it or nothing happens...
>>> task.run();
>>>
>>> That’s a single task. You can also pass an array of tasks (of all types) into a CompoundAsyncTask or a SequentialAsyncTask.
>>>
>>> CompoundAsyncTasks run all the requests in parallel. You can failEarly if you want it to complete when the first one errors. Otherwise you have the list of all the tasks when it’s done and you can loop through them to do whatever you want with the results. You can also get the completed and failed tasks separately.
>>>
>>> SequentialAsyncTask is the same, but it runs each task when the previous one finished. It passes the previous task into the next one’s run method so you can chain results.
>>>
>>> I added tasks for upload and download progress.
>>>
>>> I’d like to create one for multipart and File upload as well, but not today…
>>>
>>> IMO this architecture addresses every one of my pet peeves. I find them easy to use and reason about. I also just updated them to make it pretty difficult to create memory leaks while using them. 
>>>
>>> I hope you like it as much as me… ;-)
>>>
>>> Harbs



Re: AsyncTasks

Posted by Harbs <ha...@gmail.com>.
async/await makes things both better and worse. It lends itself to less spaghetti code at the price of more magic. The chaining problems still exist with async/await AFAIK.

I conceptually like the idea of Observables, but it’s quite a world of its own. It has a pretty large learning curve and is overkill for any use case I’ve personally had.

AsyncTasks is much less ambitious. It aims to do one thing well rather than tackling every problem in the Async space with one solution that has lots of conventions.

Also, Observables is firmly on the FP train, which I’m not. I prefer OOP solutions to functional ones.

For those not familiar with Observables and how complex/complete (depending on your perspective) it is, take a look at this: https://rxjs.dev/operator-decision-tree

FWIW, I’ve entertained the idea of creating an Observable implementation for Royale, but it was too much for me to undertake considering the chances of me wanting to use it personally is slim.

> On Oct 25, 2021, at 3:15 AM, Edward Stangler <es...@bradmark.com> wrote:
> 
> 
> I assume you're describing Promises without async / await, below.
> 
> How does your stuff compare to Observables?
> 
> 
> 
> On 10/24/2021 5:28 AM, Harbs wrote:
>> I just made a commit and I want to give some background:
>> 
>> I personally strongly dislike Promises. Promises address a need (namely callback hell), but IMO address it poorly. I find Promises unintuitive and difficult to use especially when the use case is complex. I have cases where I have a literally a chain of 35 “then” calls with various catches mixed in. It’s a nightmare to maintain.
>> 
>> Here’s my beefs with Promises
>> 1. You never actually invoke them. You declare a new Promise (or it gets spawned for you) and it magically happens on its own. I hate magic.
>> 2. The aforementioned problem makes it very difficult to control *when* the promise gets invoked.
>> 3. It’s not very intuitive how/when to resolve and reject promises.
>> 4. Promises lend themselves to nested function calls which I find very hard to read.
>> 5. Running many promises and actually dealing with the results is hard and cumbersome.
>> 6. Promise.all can help with the above, but what happens if *some* of them pass? There’s many different ways that you might want to handle that.
>> 7. There’s very little control of parallel vs serial running of promises.
>> 8. What is the result? Hard to know. I’d really like some strongly typed values to make my life easier.
>> 9. How do you deal with progress and promises? It only resolves or rejects. AFAIK, fetch has no way to get progress. How dumb is that?
>> 
>> On top of all this, I just find I always need to go back to the spec every time I use promises. I find them *very* unintuitive.
>> 
>> So I decided to do something about it. My solution is AsyncTasks.
>> 
>> I created AsyncTasks over two years ago and I’ve been using them in my app since then. (My use case was pretty specific to my needs.) I had on my to-do list to add some concrete AsyncTasks to Royale for this whole time and I was finally inspired to follow through…
>> 
>> I just created three Async classes in Network for HTTP requests and I figured now was the time to explain how to use them. ;-)
>> 
>> Basically:
>> var task: HttpRequestTask = new HttpRequestTask();
>> task.url = “https://foobaz.com/myapi <https://foobaz.com/myapi> <https://foobaz.com/myapi <https://foobaz.com/myapi>>”;
>> task.done(function(taskReturned:HttpRequestTask):void{
>> 	trace(“task is the same and taskReturned: “ + task == taskReturned);// you get the task back in the done callback
>> 	if(task.status == AsyncTask.COMPLETE){
>> 		trace(task.httpResult);
>> 		trace(task.httpStatus);
>> 	} else {// it failed you can get the status to know why
>> 		trace(task.httpStatus);
>>        }
>> });
>> // you need to run it or nothing happens...
>> task.run();
>> 
>> That’s a single task. You can also pass an array of tasks (of all types) into a CompoundAsyncTask or a SequentialAsyncTask.
>> 
>> CompoundAsyncTasks run all the requests in parallel. You can failEarly if you want it to complete when the first one errors. Otherwise you have the list of all the tasks when it’s done and you can loop through them to do whatever you want with the results. You can also get the completed and failed tasks separately.
>> 
>> SequentialAsyncTask is the same, but it runs each task when the previous one finished. It passes the previous task into the next one’s run method so you can chain results.
>> 
>> I added tasks for upload and download progress.
>> 
>> I’d like to create one for multipart and File upload as well, but not today…
>> 
>> IMO this architecture addresses every one of my pet peeves. I find them easy to use and reason about. I also just updated them to make it pretty difficult to create memory leaks while using them. 
>> 
>> I hope you like it as much as me… ;-)
>> 
>> Harbs


Re: AsyncTasks

Posted by Edward Stangler <es...@bradmark.com>.
I assume you're describing Promises without async / await, below.

How does your stuff compare to Observables?



On 10/24/2021 5:28 AM, Harbs wrote:
> I just made a commit and I want to give some background:
>
> I personally strongly dislike Promises. Promises address a need (namely callback hell), but IMO address it poorly. I find Promises unintuitive and difficult to use especially when the use case is complex. I have cases where I have a literally a chain of 35 “then” calls with various catches mixed in. It’s a nightmare to maintain.
>
> Here’s my beefs with Promises
> 1. You never actually invoke them. You declare a new Promise (or it gets spawned for you) and it magically happens on its own. I hate magic.
> 2. The aforementioned problem makes it very difficult to control *when* the promise gets invoked.
> 3. It’s not very intuitive how/when to resolve and reject promises.
> 4. Promises lend themselves to nested function calls which I find very hard to read.
> 5. Running many promises and actually dealing with the results is hard and cumbersome.
> 6. Promise.all can help with the above, but what happens if *some* of them pass? There’s many different ways that you might want to handle that.
> 7. There’s very little control of parallel vs serial running of promises.
> 8. What is the result? Hard to know. I’d really like some strongly typed values to make my life easier.
> 9. How do you deal with progress and promises? It only resolves or rejects. AFAIK, fetch has no way to get progress. How dumb is that?
>
> On top of all this, I just find I always need to go back to the spec every time I use promises. I find them *very* unintuitive.
>
> So I decided to do something about it. My solution is AsyncTasks.
>
> I created AsyncTasks over two years ago and I’ve been using them in my app since then. (My use case was pretty specific to my needs.) I had on my to-do list to add some concrete AsyncTasks to Royale for this whole time and I was finally inspired to follow through…
>
> I just created three Async classes in Network for HTTP requests and I figured now was the time to explain how to use them. ;-)
>
> Basically:
> var task: HttpRequestTask = new HttpRequestTask();
> task.url = “https://foobaz.com/myapi <https://foobaz.com/myapi>”;
> task.done(function(taskReturned:HttpRequestTask):void{
> 	trace(“task is the same and taskReturned: “ + task == taskReturned);// you get the task back in the done callback
> 	if(task.status == AsyncTask.COMPLETE){
> 		trace(task.httpResult);
> 		trace(task.httpStatus);
> 	} else {// it failed you can get the status to know why
> 		trace(task.httpStatus);
>         }
> });
> // you need to run it or nothing happens...
> task.run();
>
> That’s a single task. You can also pass an array of tasks (of all types) into a CompoundAsyncTask or a SequentialAsyncTask.
>
> CompoundAsyncTasks run all the requests in parallel. You can failEarly if you want it to complete when the first one errors. Otherwise you have the list of all the tasks when it’s done and you can loop through them to do whatever you want with the results. You can also get the completed and failed tasks separately.
>
> SequentialAsyncTask is the same, but it runs each task when the previous one finished. It passes the previous task into the next one’s run method so you can chain results.
>
> I added tasks for upload and download progress.
>
> I’d like to create one for multipart and File upload as well, but not today…
>
> IMO this architecture addresses every one of my pet peeves. I find them easy to use and reason about. I also just updated them to make it pretty difficult to create memory leaks while using them. 
>
> I hope you like it as much as me… ;-)
>
> Harbs



Re: AsyncTasks

Posted by Hugo Ferreira <hf...@gmail.com>.
That's really great.

I don't like Promises either and your approach is the .NET way.
Very clean code and easier to understand and maintain.

Harbs <ha...@gmail.com> escreveu no dia domingo, 24/10/2021 à(s)
11:27:

> I just made a commit and I want to give some background:
>
> I personally strongly dislike Promises. Promises address a need (namely
> callback hell), but IMO address it poorly. I find Promises unintuitive and
> difficult to use especially when the use case is complex. I have cases
> where I have a literally a chain of 35 “then” calls with various catches
> mixed in. It’s a nightmare to maintain.
>
> Here’s my beefs with Promises
> 1. You never actually invoke them. You declare a new Promise (or it gets
> spawned for you) and it magically happens on its own. I hate magic.
> 2. The aforementioned problem makes it very difficult to control *when*
> the promise gets invoked.
> 3. It’s not very intuitive how/when to resolve and reject promises.
> 4. Promises lend themselves to nested function calls which I find very
> hard to read.
> 5. Running many promises and actually dealing with the results is hard and
> cumbersome.
> 6. Promise.all can help with the above, but what happens if *some* of them
> pass? There’s many different ways that you might want to handle that.
> 7. There’s very little control of parallel vs serial running of promises.
> 8. What is the result? Hard to know. I’d really like some strongly typed
> values to make my life easier.
> 9. How do you deal with progress and promises? It only resolves or
> rejects. AFAIK, fetch has no way to get progress. How dumb is that?
>
> On top of all this, I just find I always need to go back to the spec every
> time I use promises. I find them *very* unintuitive.
>
> So I decided to do something about it. My solution is AsyncTasks.
>
> I created AsyncTasks over two years ago and I’ve been using them in my app
> since then. (My use case was pretty specific to my needs.) I had on my
> to-do list to add some concrete AsyncTasks to Royale for this whole time
> and I was finally inspired to follow through…
>
> I just created three Async classes in Network for HTTP requests and I
> figured now was the time to explain how to use them. ;-)
>
> Basically:
> var task: HttpRequestTask = new HttpRequestTask();
> task.url = “https://foobaz.com/myapi <https://foobaz.com/myapi>”;
> task.done(function(taskReturned:HttpRequestTask):void{
>         trace(“task is the same and taskReturned: “ + task ==
> taskReturned);// you get the task back in the done callback
>         if(task.status == AsyncTask.COMPLETE){
>                 trace(task.httpResult);
>                 trace(task.httpStatus);
>         } else {// it failed you can get the status to know why
>                 trace(task.httpStatus);
>         }
> });
> // you need to run it or nothing happens...
> task.run();
>
> That’s a single task. You can also pass an array of tasks (of all types)
> into a CompoundAsyncTask or a SequentialAsyncTask.
>
> CompoundAsyncTasks run all the requests in parallel. You can failEarly if
> you want it to complete when the first one errors. Otherwise you have the
> list of all the tasks when it’s done and you can loop through them to do
> whatever you want with the results. You can also get the completed and
> failed tasks separately.
>
> SequentialAsyncTask is the same, but it runs each task when the previous
> one finished. It passes the previous task into the next one’s run method so
> you can chain results.
>
> I added tasks for upload and download progress.
>
> I’d like to create one for multipart and File upload as well, but not
> today…
>
> IMO this architecture addresses every one of my pet peeves. I find them
> easy to use and reason about. I also just updated them to make it pretty
> difficult to create memory leaks while using them.
>
> I hope you like it as much as me… ;-)
>
> Harbs