Y-yield

Y-yield is a way to get back to the wonderful land of reliable exceptions and easy to follow asynchronous code using Javascript. Any caveats? Well, it requires the use of upcoming standard ECMAScript 6, so it's anything but mainstream at the moment. However, chances are that the standard is going to be approved during 2013 and then it will only be a matter of time before all browsers (ehm..) have implemented the feature. The new standard gives us syntactical goodies such as "function*" and "yield". But, you may ask yourself, what does it provide? Why yield?

The basic idea

ECMAScript 6 introduces something called generators. They look like this:

function*myGenerator(){

yield"SomeValue";

yield"SomeOtherValue";

}

var a =myGenerator();

var value =a.next();// first line in myGenerator executes, returns "SomeValue"

var otherValue =a.next();// second line in myGenerator executes, returns "SomeValue"

Ok...that looks pretty much like Python/Scala/C#/whatever. What does that bring in terms of asynchronous code? Well, the idea is that if we can write our code as a generator generating different asynchronous pieces of code, we can use the built-in wrapping/unwrapping of function bodies and try/catch statements to make our life easier. We could write something like

function*fetchUrl(){

...

}

function*getTodos(extra){

try{

var todosTask =fetchUrl("/todos");

var emailTask =fetchUrl("/todos");

// Wait for the two parallel tasks to finish

var todosAndEmail =yield[todosTask, emailTask];

console.log("All fetched", todos, email);

}

catch(e){

console.error("Oops...something went wrong", e);

}

}

Note that the generators return objects that we have to "yield" to see the result for. If you get that, you get what it's about.

And to just make the "why yield" answer a little clearer:

Ever used an async library and just get lost. Where did that call go? No reply, no error, no nothing. Rescue is under way.

We can use try/catch again. You've read the posts about avoiding those pesky keywords in asynchronous code (i.e. all code) as you can't rely on them being called. But hey, remember that convenient idea of wrapping a bunch of calls in try/catch and handling a lot of different errors in a grouped way for a piece of code. Perhaps being able to send an error back or outputting to some log. Sure, there are solutions in old callback land such as node domains, load balancing workers, and it may be a good idea to die rather than to do stupid things. But, being pragmatic, it's pretty nifty to be able to actually catch all errors within a block of code and decide for yourself.

Ever felt a little bad about cluttering your objects, parameters and classes with callbacks here and there. Get ready for cleaner code.

Ever written some asynchronous code and made a mistake in the error handler? Maybe you forgot to add one? Maybe your colleague did? Maybe you typed it incorrectly and now your application has just not returned from a call in quite some time. Console is just blank. :(

There are all kind of libraries to make asynchronous coding easier. Among the most popular are async in node, jQuery Deferred and Q. But there are oh so many ways different libraries handle this. jQuery use its own deferreds and node uses the passing of a function with one callback function. Sequalize, a MySQL ORM, uses a notion of chaining success and error callbacks. And still other libraries use an option parameter with a success/error callback. For anyone coding javascript, especially in node, it's evident that these conversions take time, are error prone and leave an uneasy feeling of possibly missing something. And even if we don't consider errors, it's often pretty darn hard to follow what's happening, especially if there's a bit of conditional asynchronous extra calls.

Asyncronous stack traces? It is pretty saddening to just see that EventEmitter in your stack trace, right? With that said, there are node packages to make it easier such as trycatch.

ECMAScript is in a way catching up with this. Async handling has been major recent lanaguage features in languages such as C#, F#, Scala,

So let's try it out!
If you want to look at more examples, please have a look at the tests.

After that script include, include yyield. AMD is not implemented yet. Please use either:

<script src="yyield.js"></script>

...or require("yyield") with [RequireJS](http://requirejs.org/) and r.js

Now Y-yield is accessible through window.Y. If something else was previuosly attached you can reach it at window.Y.noConflict

What about IE/Firefox/Opera/Safari/PhantomJS/etc?

I will add supprt and tests as those browsers support generators. At present, they don't

Usage

(function*(){

// Here we run our async program

}).run();

Ways of doing async - "yieldable things"

You can "yield" all sort of stuff to make life easier, e.g.:

A normal async node function

function*sleep(timeout){

yieldfunction(cb){setTimeout(function(){cb(null);}, timeout);}

}

Another generator

function*sleep(timeout){

yieldfunction(cb){setTimeout(function(){cb(null);}, timeout);}

}

(function*(){

yieldsleep(1000);

}).run();

You can always write "return" instead of yield as the last statement

The above example then becomes

function*sleep(timeout){

returnfunction(cb){setTimeout(function(){cb(null);}, timeout);}

}

(function*(){

returnsleep(1000);

}).run();

A converted object or function

You can convert objects or functions by using the exported "gen" function. This assumes that all functions have the format

function(...,cb)

...where cb is a callback on the form callback(error, [resultArguments])

Some examples:

var Y =require("yield");

var lib =require("somelib")

var genlib =Y.gen(lib);

var genObj =Y.gen(newlib.SomeClass());

var genFunc =Y.gen(lib.someFunction);

(function*(){

var a =yieldgenlib.someFunction(...);

var b =yieldgenObj.someInstanceFunction(...);

var c =yieldgenFunc(...);

}).run();

Note that when converting an object, "this scope" is preserved. It is not when you convert a single function. Also - conversions are shallow (just one level of functions) and return values are not converted. Thus - if you require a library which exports a class that you construct, by using

var myClassInstance =newlib.MyClass();

...then you also have to convert the myClassInstance to use generators, by using

var genMyClassinstance =require("yield").gen(myClassInstance);

The Y-yield generators work fine with promises such as Q.defer and jQuery.Deferred

By using promises based asynchornous flows, you are able to chain calls with multiple calls to .then() in e.g. Q or jQuery. You can mix this with calls to done/fail to create way to accomplish asynchronous data flows.

Here's an example using jQuery Deferred (namely the quite common return object form $.ajax/getJSON)

(function*(){

try{

var newTodos =yield$.getJSON("/todos/new");

alert(newTodos.length+" new todos found.");

}

catch(e){

console.error(e.stack);

}

}

}).run();

Y also integrates with these by returning promises from the run method. Note that promises are only returned if you're running in node or requirejs (by using Q) or if you're running in a browser and jQuery exists. Y-yield does not require that Q or jQuery are installed and will work fine without them - only run will not return anything. Here's an example where we use Y-yield to chain on a then function: