EasilyBaffled
EasilyBaffled

Reputation: 3882

Why does generator's .next need a setTimeout?

I'm experimenting with ES6's generator functions and yield statements, Example.

function run(generator) {
  var itr = generator(resume);

  function resume(callbackValue) {
    itr.next(callbackValue);
  }
  itr.next();
}

function* main(resume) {
  var result1 = yield add(1, resume);
  var data1 = result1;
  console.log("add 1 = ", data1)
  var data2 = yield add(1, resume);
  console.log("add 1 = ", data2);
  var data3 = yield add(data1, resume);
  console.log("add data1 =", data3);
  console.log("total is ", data1 + data2 + data3);
}

function add(num, resume) {
  setTimeout(function() {
    resume(num + 1);
  }, 0);
}

run(main);

I plan on using yield as flow control for asynchronous REST calls, where the request will call next once it has a response, but for now I'm just using a simple adding function. It works as planned which is exciting but resume will only work with in the setTimeout and I'm not sure why. If it just have:

function add (num, resume) {
    resume(num + 1);
} 

the interpreter gives me 'Generator is already running'.

There doesn't need to be an actual wait in the time for the timeout, and I also tried a self invoking function, but that didn't help. Why does itr.next() need a timeout?

Upvotes: 4

Views: 1972

Answers (1)

tablekat
tablekat

Reputation: 31

As other commenters said, you're trying to call resume while the yield expression is still resolving. Asynchronously calling itr.next will allow the yield expression to finish, and then immediately call itr.next when it's done. To get it to work the way you want, just change run:

function run(generator) {
  var itr = generator(resume);

  function resume(callbackValue) {
    setTimeout(function(){
      itr.next(callbackValue);
    }, 0);
  }
  itr.next();
}

This is a really fun idea, and it could actually be useful.

Upvotes: 3

Related Questions