Generator

Mia Yang

  • Generators + Promises
  • Promise-Aware Generator Runner
  • Async & Await
  • Promise Concurrency in Generators
  • Generator Delegation
  • Thunk
Generators + Promises
// 假想成第三方非同步函式
function request(x, y, cb) {
  return new Promise((resolve, reject) => {
    setTimeout(cb, 1000, x, y)
  })
}

function cb(x, y) {
  (x + y) % 2 === 0 ? it.next('YEAH') : it.throw('ERROR')
}

function* main() {
  try {
    var text = yield request(10, 31, cb)
    console.log('Success', text)
  }
  catch (err) {
    console.error('Catch', err)
  }
}

var it = main()

it.next() // Catch ERROR
function request(x, y) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      (x + y) % 2 === 0 ? resolve('YEAH') : reject('ERROR')
    }, 1000)
  })
}

function* main() {
  try {
    var text = yield request(10, 31)
    console.log('Success', text)
  }
  catch (err) {
    console.error('Catch', err)
  }
}

var it = main();
var p = it.next().value

p
  .then((text) => {
    it.next(text);
  })
  .catch((err) => {
    it.throw(err);
  })

// Catch ERROR
Promise-Aware Generator Runner
function step(gen) {
	var it = gen();
	var last;

	return function() {
		last = it.next( last ).value;
	};
}

a = 1;
b = 2;

var s1 = step( foo );
var s2 = step( bar );

s2();		
s2();		
s1();		
s2();		
s1();		
s1();		
s2();
function *foo() {
	var x = yield 2;
	z++;
	var y = yield (x * z);
	console.log( x, y, z );
}

var z = 1;

var it1 = foo();
var it2 = foo();

var val1 = it1.next().value;			
var val2 = it2.next().value;			

val1 = it1.next( val2 * 10 ).value;		
val2 = it2.next( val1 * 5 ).value;		

it1.next( val2 / 2 );					
									
it2.next( val1 / 4 );	
function run(gen) {
  let args = [].slice.call(arguments, 1)
  let it = gen.apply(this, args);

  return Promise.resolve()
    .then(function handleNext(value) {
      var next = it.next(value);

      return (function handleResult(next) {
        if (next.done) { return next.value; }
        else {
          return Promise.resolve(next.value)
            .then(
              handleNext,
              function handleErr(err) {
                return Promise.resolve(it.throw(err))
				  .then(handleResult);
              }
            );
        }
      })(next);
    });
}

run(main)

// Success1 YEAH
// Catch ERROR
function foo(x, y) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      (x + y) % 2 === 0 ? resolve('YEAH') : reject('ERROR')
    }, 1000)
  })
}

function* main() {
  try {
    var text = yield foo(11, 31)
    console.log('Success1', text)
    var text = yield foo(10, 31)
    console.log('Success2', text)
  }
  catch (err) {
    console.error('Catch', err)
  }
}

co

var co = require('co');

function foo(x, y) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      (x + y) % 2 === 0 ? resolve('YEAH') : reject('ERROR')
    }, 1000)
  })
}

function* main() {
  try {
    var text = yield foo(11, 31)
    console.log('Success1', text)
    var text = yield foo(10, 31)
    console.log('Success2', text)
  }
  catch (err) {
    console.error('Catch', err)
  }
}

co(main)

// Success1 YEAH
// Catch ERROR
Async & Await
function foo(x, y) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      (x + y) % 2 === 0 ? resolve('YEAH') : reject('ERROR')
    }, 1000)
  })
}

async function main() {
  try {
    var text = await foo(11, 31)
    console.log('Success1', text)
    var text = await foo(10, 31)
    console.log('Success2', text)
  }
  catch (err) {
    console.error('Catch', err)
  }
}

main()
Promise Concurrency in Generators
function foo(x, y) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      (x + y) % 2 === 0 ? resolve(x + y) : reject('ERROR')
    }, 1000)
  })
}

function* main() {
  try {
    var temp = yield Promise.all([foo(11, 31), foo(11, 31)])
    console.log(temp)
    let result = yield foo(temp[0], temp[1])
    console.log(result)
  }
  catch (err) {
    console.error('Catch', err)
  }
}

co(main)

// [42, 42]
// 84
Generator Delegation
function *foo() {
	console.log( "`*foo()` starting" );
	yield 3;
	yield 4;
	console.log( "`*foo()` finished" );
}

function *bar() {
	yield 1;
	yield 2;
	yield *foo();	// `yield`-delegation!
	yield 5;
}

var it = bar();

it.next().value;	// 1
it.next().value;	// 2
it.next().value;	// `*foo()` starting
					// 3
it.next().value;	// 4
it.next().value;	// `*foo()` finished
					// 5
function *foo() {
	var r2 = yield request( "http://some.url.2" );
	var r3 = yield request( "http://some.url.3/?v=" + r2 );

	return r3;
}

function *bar() {
	var r1 = yield request( "http://some.url.1" );

	// 通过`run(..)`“委托”到`*foo()`
	var r3 = yield run( foo );

	console.log( r3 );
}

run( bar );
function* foo() {
  console.log("inside `*foo()`:", yield "B");
  console.log("inside `*foo()`:", yield "C");
  return "D";
}

function* bar() {
  console.log("inside `*bar()`:", yield "A");
  console.log("inside `*bar()`:", yield* foo());
  console.log("inside `*bar()`:", yield "E");

  return "F";
}

var it = bar();

console.log("outside:", it.next().value);
// outside: A

console.log("outside:", it.next(1).value);
// inside `*bar()`: 1
// outside: B

console.log("outside:", it.next(2).value);
// inside `*foo()`: 2
// outside: C

console.log("outside:", it.next(3).value);
// inside `*foo()`: 3
// inside `*bar()`: D
// outside: E

console.log("outside:", it.next(4).value);
// inside `*bar()`: 4
// outside: F
function* bar() {
  console.log("inside `*bar()`:", yield "A");
  console.log("inside `*bar()`:", yield* ["B", "C", "D"]);
  console.log("inside `*bar()`:", yield "E");

  return "F";
}

var it = bar();

console.log("outside:", it.next().value);
// outside: A

console.log("outside:", it.next(1).value);
// inside `*bar()`: 1
// outside: B

console.log("outside:", it.next(2).value);
// outside: C

console.log("outside:", it.next(3).value);
// outside: D

console.log("outside:", it.next(4).value);
// inside `*bar()`: undefined
// outside: E

console.log("outside:", it.next(5).value);
// inside `*bar()`: 5
// outside: F
var something = (function () {
  var nextVal;

  return {
    [Symbol.iterator]: function () { return this; },
    next: function () {
      if (nextVal === undefined) {
        nextVal = 1;
      }
      else {
        nextVal = (3 * nextVal) + 6;
      }
      return nextVal > 500
        ? { done: true, value: nextVal }
        : { done: false, value: nextVal }
    }
  };
})();

function* bar() {
  console.log("inside `*bar()`:", yield "A");
  console.log("inside `*bar()`:", yield* something);
  console.log("inside `*bar()`:", yield "E");

  return "F";
}


run(bar) 

// inside `*bar()`: A
// inside `*bar()`: 969
// inside `*bar()`: E
function* foo() {
  try {
    yield "B";
  }
  catch (err) {
    console.log("error caught inside `*foo()`:", err);
  }
  yield "C";
  throw "D";
}

function* bar() {
  yield "A";
  try {
    yield* foo();
  }
  catch (err) {
    console.log("error caught inside `*bar()`:", err);
  }

  yield "E";
  yield* baz();
  // note: can't get here!
  yield "G";
}

function* baz() {
  throw "F";
}
var it = bar();

console.log("outside:", it.next().value);
// outside: A

console.log("outside:", it.next(1).value);
// outside: B

console.log("outside:", it.throw(2).value);
// error caught inside `*foo()`: 2
// outside: C

console.log("outside:", it.next(3).value);
// error caught inside `*bar()`: D
// outside: E

try {
  console.log("outside:", it.next(4).value);
}
catch (err) {
  console.log("error caught outside:", err);
}
// error caught outside: F
function* foo(val) {
  console.log('input', val)
  if (val > 1) {
    val = yield* foo(val - 1);
  }
  return yield request(val);
}

function request(x) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(`result:${x*2}`)
      resolve(x * 2)
    }, 1000)
  })
}

function* bar() {
  var r1 = yield* foo(3);
  console.log(r1);
}

run(bar);


// input 3
// input 2
// input 1
// result:2
// result:4
// result:8
// 8
Thunk
function foo(x, y, cb) {
  setTimeout(function () {
    cb(x + y);
  }, 1000);
}

function fooThunk(cb) {
  foo(3, 4, cb);
}


fooThunk(function (sum) {
  console.log(sum); // 7
});
function thunkify(fn) {
  var args = [].slice.call(arguments, 1);
  return function (cb) {
    args.push(cb);
    return fn.apply(null, args);
  };
}

var fooThunk = thunkify(foo, 3, 4);


fooThunk(function (sum) {
  console.log(sum);		// 7
});
function thunkify(fn) {
  return function () {
    var args = [].slice.call(arguments);
    return function (cb) {
      args.push(cb);
      return fn.apply(null, args);
    };
  };
}
var fooThunkory = thunkify(foo);

var fooThunk1 = fooThunkory(3, 4);
var fooThunk2 = fooThunkory(5, 6);


fooThunk1(function (sum) {
  console.log(sum);		// 7
});

fooThunk2(function (sum) {
  console.log(sum);		// 11
});
Made with Slides.com