Task.js Asynchronous Tasks In JavaScript
Written by Mike James   
Monday, 06 May 2013
Article Index
Task.js Asynchronous Tasks In JavaScript
A First Example

There are some interesting things going on the latest version of JavaScript and already some new uses are being found for them. Task.js uses the new generator facility to build an asynchronous task facility. 

If you know a little JavaScript then you will also know that asychronous programming is key to making it work correctly. You can't simply hog the single thread of execution. If you do so the result is that the system and the UI grind to a halt. Yet for a language that depends on asychronous programming JavaScript has little to offer in to help with what can be a very messy programming idiom. 

The best that is currently on offer is the Promise or the Deferred object in jQuery. This allows asychronous functions to return a Promise object immediately and for the client to code to specify the function to run when the Promise resolves.

This is an improvement on the basic callback mechanism but it still makes a bit of a mess of the natural layout of the code and it can produces a nested mess if you need to have multiple Promises.

At the moment perhaps the best solution to the asychronous problem is C#'s async and await commands and we have to hope that one day JavaScript will have something similar. In the mean time Mozilla has a nice experiment that makes use of the new generator function facility in ES6. The big problem is that at the moment only Firefox supports generators.

First let's take a look a the idea of a generator - yield and send. 

The Generator

If you haven't encountered the generator idea it is fairly simple.

If you write

yield expression

in a function it becomes a generator.

If you call the function it returns an iterator object which has a next method.

Each time you call the next method the iterator executes the code of the original function until it encounters a yield when it halts and returns the value. When the next method is called again the execution begins at the instruction following the yield. The yield mechanism is a simple form of continuation. 

 For example:

function myGen()
{
 
yield 1;
 yield 2;
 
yield 3;

}

then 

var gen=myGen();
gen.next()

returns 1

gen.next()

returns 2

and so on. 

The calling routine can also send a return result to a yield by using the generators send method. If you use 

gen.send(0);

in place of next() then the yield returns zero:

var answer=yield 1;

stores zero in answer. Notice that if the calling routine uses next to resume after the yield then answer is set to undefined - something not very clear from the documentation.

In normal use the send method is used to reset or modify the sequence that the generator produces, but Task.js uses it for a completely different purpose. 

To see a generator in action as it was intended to be used the almost standard example is to create a Fibbonaci generator. 

First to make any of the following work you have to be using Firefox and you have to load the script using:

<script type="application/javascript;version=1.8">

Following this you can use yield:

function myFib(){
 var v1=0;
 var v2=1;
 while(true){
  yield v1;
  v2=v1+v2;
  v1=v2-v1;
 }
}

Once defined you can use it to iterate through the Fibbonaci numbers:

var fib=myFib();
console.log(fib.next()); console.log(fib.next()); console.log(fib.next()); console.log(fib.next()); console.log(fib.next());

which prints 0,1,1,2,3 and so on. 

If you want to allow the caller to reset the generator you can do it something like:

function myFib(){
 var v1=0;
 var v2=1;
 while(true){
  var restart=yield v1;
  v2=v1+v2;
  v1=v2-v1;
  if(restart){ v1=0; v2=1; }
 }
}

and call it as; 

console.log(fib.send(true));

to restart it. Notice that we don't have to test for undefined in this case because, by JavaScript's truthyness rules, undefined is treated as false. 

 

Banner

 

Task.js

So far we have seen the standard use of yield. What Task.js does is to take the yield statement and use it to implement not an iterator but a co-operative task interrupt.

The idea is that you write a function which yields each time it wants, or needs, to allow something else to happen. The clever part is that it yields a Promise object, which the scheduler uses to restart your function flowing the yield when the Promise resolves. 

So the pattern used by Task.js is:

Your function runs until it reaches a point where it needs to wait for some asychronous operation or because it wants to give some other task a chance to run.

At this point is yields on an operation that returns a Promise that is resolved when the operation is complete.

The scheduler receives the Promise object and starts another Task or relinquishes the UI thread so that events can be processed.

When Promise object is resolved the task that blocked on it is restarted using its send(value) method. The causes result or value of the promise is returned as the value of the yield. 

That's all there is to it and it is very simple.

The real beauty of this approach is that when you just look at the code you have to write it looks very simple even if there is a lot going on behind the scenes.

To make Task.js work you have to load it so include: 

<script type="application/javascript" src="/task.js">
</script>

Now you can start to work with Task.js but remember to start your scripts with:

<script type="application/javascript;version=1.8">



Last Updated ( Tuesday, 15 October 2013 )