Generators

Generators are functions that can be paused in mid execution. You recognize a generator by declaring itself with a * in the function prototype and a yield in the function body :

function * generator(){
  yield 1;
  yield 2;
}

This function can be called multiple times with different results. It will move its pointer, if you will from one yield to the next. To get the value from the generator function you need to call the next() method. This will return an object consisting of the properties value and done.

Like so:

let gen = generator();
gen.next() // { value: 1, done: false }
gen.next() // { value: 2, done: false }
gen.next() // { value: undefined, done: true }

Sending values to your generator

function *generator(){
  var x = yield 1;
  yield "hi" + x;
}

Calling the generator like this:

var gen = generator();
gen.next();  // { value: 1, done : false }
gen.next('chris') // { value: 'hi chris', done : false }

What happens here is that the first yield is being triggered when calling next(). On the second call to next() the statement yield 1 is being replaced with what we send into the next() statement which is chris so it reads like hi chris, which is what we are getting out.

Using it with promises

Using generators with promises is quite easy. What you need is to make sure that what you are yielding is instead a promise like so:

function getData(){
   return Promise.resolve(5);
}


function* generator(){
  yield getData();
}

var gen = generator();
gen.next().value
.then(function(data){
  console.log(data) // 5
})

Using it with co lib

Co is a fanastic little lib found at link to co It can be easily installed with:

npm install co

It works like the following:


function getData(){
  return Promise.resolve( 1 )
}

function getMoreData(){
  return Promise.resolve( 2 ); 
}

function evenMore(){
  return Promise.resolve( 3 );
}

function getError(){
  return Promise.reject( 'err' );
}

co(function* (){
   try {
      var data = getData();
      var moreData = getMoreData();
      var evenMore = evenMore();
   } catch (err) {
      console.log(err)  // err 
   }
})

To see why this is great for existing apps let's look at how it can really transform an AngularJS project.

not using co

angular.module('app', [])
.controller('ctrl', function(){
  let vm = this;

  function init(){
     authorize()
       .then(getUser)
       .then(getOrdersByUser)
       .catch((err) => vm.error = err)
  }

  init(); 


})

using co

angular.module('app', [])
.controller('ctrl', function(){
  let vm = this;

   co(function* (){
     try {
        var authorized = authorize();
        var user = getUser( authorized );
        var evenMore = getOrdersByUser( user.id );

        vm.data = { data : data, moreData : moreData, evenMore : evenMore  }
     } catch (err) {
        vm.error = err;
     }
  })

})

It should also be mentioned that co returns a Promise so you are able to do the following:

 co(function*(){
   var data = yield getData();

   return data
 })
 .then( data => console.log(data) )
 .catch( err => console.error(err) )

The number of lines of code is about the same but it is so much more readable without then() and catch() and it looks synchronous - achievement unlocked

Here is a github repo showing how you could use it with AngularJS Angular with generators

results matching ""

    No results matching ""