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)
}
}
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
});