Skip to content

Latest commit

ย 

History

History
588 lines (453 loc) ยท 10.9 KB

4_Generators.md

File metadata and controls

588 lines (453 loc) ยท 10.9 KB

Generators

์š”์•ฝ

Name URL
holee
sunpark
dongbkim
gim
sohpark
nkang
yujo

Quiz

4.1 ใ€€ Breaking Run-to-Completion

dongbkim

  1. ๋‹ค์Œ ์ฝ”๋“œ์˜ ๊ฒฐ๊ณผ๋ฅผ ์˜ˆ์ธกํ•˜๊ณ  ๋ฒ„๊ทธ๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ณ ์น˜์‹œ์˜ค.
    (1)
function *foo(){
	yield 1;
	yield 2;
	yield 3;
	return 5;
}

var it = foo();
while(it.done != true)
{
	console.log(it.next());
}

(2)

let x = 1;
let y = 10;

function *bar(){
	x--;
	x = (yield x) + y;
	yield;
	x += 10;
	x *= (yield 2);
}

function *baz(){
	var b = (yield 1);
	y = (yield b) + x;
	y += (yield 1);
	x -= yield 20;
	console.log(x + y);
}

function step(gen){
	var it = gen();
	var last;

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

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

s1();
s1();
s2();
s1();
s2();
s2();
s1();
s2();
s2();

(3)

let x = 1;
let y = 10;

function *bar(){
	x--;
	x = (yield x) + y;
	yield;
	x += 10;
	x *= (yield 2);
	x--;
}

function *baz(){
	var b = (yield 1);
	y = (yield b) + x;
	y += (yield 1);
	x -= yield 20;
	console.log(x + y);
}

function step(gen){
	var it = gen();

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

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

s1();
s1();
s2();
s1();
s2();
s2();
s1();
s2();
s2();
๐Ÿ“„ ๋‹ต์ง€
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: 5, done: true }
{ value: undefined, done: true }
{ value: undefined, done: true }
{ value: undefined, done: true }
.
.
.

๊ณ ์นœ ์ฝ”๋“œ

function *foo(){
	yield 1;
	yield 2;
	yield 3;
	return 5;
}

var it = foo();
// var buf = it.next();
// console.log(buf);

// while(buf.done !== true)
// {
// 	buf = it.next();
// 	console.log(buf);
// }

var buf;
do {
	buf = it.next();
	console.log(buf);
} while(buf.done !== true);

(2) 42
(3) 42


4.2 ใ€€ Generator'ing Values

gim

  1. ___ ๋Š” producer๋กœ์„œ ์ด์ „์˜ ๊ฐ’๊ณผ ์—ฐ๊ด€๋œ ๊ฐ’์„ ์—ฐ์†์ ์œผ๋กœ ์ œ๊ณตํ•œ๋‹ค. ์ด๋Š” ์™ธ๋ถ€์—์„œ ํ•ด๋‹น ์Šค์ฝ”ํ”„์˜ ๊ฐ’์„ ์ฐธ์กฐํ•˜๋Š” ๊ฐœ๋…์ธ ___ ๋ฅผ ์ฐจ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋Šฅํ•œ ๋””์ž์ธ ํŒจํ„ด์ด๋‹ค.
  2. producer์—์„œ ์ œ๊ณตํ•œ ๊ฐ’์„ ๋‹จ๊ณ„์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ€์žฅ ์ ํ•ฉํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋Š” ___ ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.
  3. for..of ๊ตฌ๋ฌธ์˜ ๋™์ž‘ ๋ฐฉ์‹
  • ์ฐธ์กฐํ•˜๋ ค๋Š” ๊ฐ์ฒด๊ฐ€ ___ ์ธ์ง€ ํ™•์ธํ•œ๋‹ค.
  • ํ•ด๋‹น ๊ฐ์ฒด์˜ ___ ๋ฉ”์„œ๋“œ๋ฅผ ์ž๋™์œผ๋กœ ํ˜ธ์ถœํ•œ๋‹ค.
  • ์œ„ ๋ฉ”์„œ๋“œ๋กœ ๋ฐ˜ํ™˜๋œ ___ ๊ฐ์ฒด์˜ ___ ๋ฉ”์„œ๋“œ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ํ˜ธ์ถœํ•˜์—ฌ ํ•ด๋‹น value๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.
  1. generator function ๋˜ํ•œ for..of ๋ฌธ์„ ํ†ตํ•ด ์—ฐ์†์ ์ธ ๊ฐ’์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ง์ ‘ ํ˜ธ์ถœ์„ ํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š”๋ฐ, ๊ทธ ์ด์œ ๋Š” ๋ฌด์—‡์ผ๊นŒ?
for (let value of generator()) { // why?
    logic...
}
  1. generator ์˜ iterator ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” for..of ๊ตฌ๋ฌธ์—์„œ break ๋ฅผ ์‚ฌ์šฉํ•œ ์ข…๋ฃŒ๋Š” ํ•ด๋‹น ๊ฐ์ฒด์— ๋Œ€ํ•œ ๋ถˆ์™„์ „ํ•œ ์™„๊ฒฐ์„ฑ์„ ๊ฐ€์ง„๋‹ค. ๊ทธ๋ ‡๊ธฐ์— ์‚ฌ์šฉ์ž ์ธก๋ฉด์—์„œ ์™„๊ฒฐ์„ฑ์„ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด ___ ๊ตฌ๋ฌธ๊ณผ iterator ๊ฐ์ฒด์˜ ___ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
๐Ÿ“„ ๋‹ต์ง€
  1. Generator / Closure
  2. Iterator
  3. iterable / Symbol.iterator / iterator / next
  4. for..of๋Š” iterable์„ ํ•„์š”๋กœ ํ•œ๋‹ค. generator function ์—์„œ ๋ฐ˜ํ™˜๋œ iterator ๊ฐ์ฒด๋Š” Symbol.iterator์™€ next๋ฅผ ๋ชจ๋‘ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— iterable ์ด๋ฉด์„œ iterator ๋ผ๊ณ  ๋ณธ๋‹ค.
  5. try..finally / return

4.3 ใ€€ Iterating Generators Asynchronously

gim

  1. ๊ธฐ์กด์˜ ์ฝœ๋ฐฑ์„ ์‚ฌ์šฉํ•œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์™€ ๋น„๊ตํ–ˆ์„ ๋•Œ, ๋‹ค์Œ ์ฝ”๋“œ๋กœ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์ด์ ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐ ํ•ด๋ด…์‹œ๋‹ค.
function foo() {
  ajax(url, (err, data) => {
    if (err) {
      it.throw(err);
    } else {
      it.next(data);
    }
  });
}

function* main() {
  try {
    var text = yield foo();
    console.log(text);
  } catch (err) {
    console.error(err);
  }
}

var it = main();

it.next();
๐Ÿ“„ ๋‹ต์ง€
  1. async-await ์˜ await ๊ด€์ ์œผ๋กœ ๋ณด๋ฉด ์ข€ ๋” ์ดํ•ด ํ•˜๊ธฐ ํŽธํ•˜๋‹ค.
    • it.next() ๋ฅผ ํ˜ธ์ถœ ํ•˜๋ฉด ๋งจ ์ฒ˜์Œ yield ์ง€์ ์˜ foo()๋ฅผ ํ˜ธ์ถœ.
    • foo() ์˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ๋๋‚  ๋•Œ๊นŒ์ง€ *main์˜ ํ›„์ˆœ์œ„ ๋กœ์ง์€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
    • ajax() ์—์„œ ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ํŒ๋‹จํ•˜์—ฌ it ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๊ทธ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋Š” *main ์—์„œ ์ˆ˜ํ–‰ํ•œ๋‹ค.

์ด์™€ ๊ฐ™์€ ํ๋ฆ„์œผ๋กœ 'ajax ์š”์ฒญ -> ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ' ์˜ ๋™๊ธฐ(์ฒ˜๋Ÿผ ๋ณด์ด๋Š”) ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.


4.4 ใ€€ Generators + Promises

sohpark

  1. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ”„๋ผ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์™€ ์ œ๋„ค๋ ˆ์ดํ„ฐ๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์„ ๋•Œ, Hello World๋ฅผ ์ถœ๋ ฅํ•˜๊ฒŒ ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ์ง€ then์„ ์ด์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”.
function apiCall(x) {
  return Promise.resolve(x); // ๋น„๋™๊ธฐ ํ•จ์ˆ˜. Promise ๋ฐ˜ํ™˜
}

function* main() {
  try {
    let result = yield apiCall('Hello World');
    console.log(result);
  } catch (err) {
    console.error(err);
  }
}
  1. ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ๋ณด๊ณ  ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋Š” ์ด์•ผ๊ธฐ ์ค‘ ์˜ณ์ง€ ์•Š์€ ๊ฒƒ์€?
function apiCall(x) {
  return Promise.resolve(x); // ๋น„๋™๊ธฐ ํ•จ์ˆ˜. Promise ๋ฐ˜ํ™˜
}

function* gen() {
  let val1 = yield apicall('someurl01');
  let val2 = yield apicall('someurl02');

  let val3 = yield apicall('someurl' + val1 + val2);

  console.log(val3);
}

run(gen);
  • run ํ•จ์ˆ˜๋Š” ์ธ์ž๋กœ ๋ฐ›์€ ์ œ๋„ค๋ฆฌ์ดํ„ฐ ์•ˆ์—์„œ promise๋ฅผ yield ํ•˜๋ฉด resolve๋œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ๋” ๋„์™€์ฃผ๋Š” ํ•จ์ˆ˜์ด๋‹ค.
  • genํ•จ์ˆ˜๊ฐ€ ์ œ๋„ค๋ ˆ์ดํ„ฐ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด yield๋Œ€์‹  await๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.
  • ์ œ๋„ค๋ฆฌ์ดํ„ฐ ํŠน์„ฑ์ƒ val1, val2๋Š” ๋ณ‘๋ ฌ ์ž‘์—…์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
๐Ÿ“„ ๋‹ต์ง€
let it = main();
let p = it.next().value;
p.then(
  res => {
    it.next(res);
  },
  err => {
    it.throw(err);
  }
);
  1. ์ œ๋„ค๋ฆฌ์ดํ„ฐ ํ•จ์ˆ˜์˜ ํŠน์„ฑ์ƒ val1, val2๋Š” ๋ณ‘๋ ฌ ์ž‘์—…์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.๋Š” ์ž˜๋ชป๋œ ๋ง๋กœ, val1๊ณผ val2๋ฅผ ์–ป์–ด์˜ค๋Š” Promise๋Š” ๋ณ‘๋ ฌ์ ์œผ๋กœ ์ž‘์—…์ด ๊ฐ€๋Šฅํ•˜๋‹ค. yield์™€ Promise.all์„ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”๋ฐ, ์ฑ…์—์„œ ์†Œ๊ฐœ๋œ ๋ฐฉ๋ฒ•๋“ค์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
function* gen() {
  let p1 = apicall('someurl01');
  let p2 = apicall('someurl02');

  let val1 = yield p1;
  let val2 = yield p2;

  let val3 = yield apicall('someurl' + val1 + val2);

  console.log(val3);
}
function* gen() {
  let vals = yield Promise.all([apicall('someurl01'), apicall('someurl02')]);

  let [val1, val2] = vals;

  let val3 = yield apicall('someurl' + val1 + val2);

  console.log(val3);
}

4.5 ใ€€ Generator Delegation

nkang

๋‹ค์Œ ์ฝ”๋“œ์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ์“ฐ์‹œ์˜ค.

function *innerGenerator() {
  yield *['a', 'b', 'c'];
}

function *generator() {
  yield *[1, 2, 3];
  const innerGen = innerGenerator();
  console.log(innerGen);
  yield *innerGenerator();
}

[...generator()];
๐Ÿ“„ ๋‹ต์ง€
Iterator [Generator] {}
[ 1, 2, 3, 'a', 'b', 'c' ]

์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋Š” yield * ๋ฅผ ํ†ตํ•˜์—ฌ ๋‹ค๋ฅธ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. innerGeneration๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜๋˜์ง€๋งŒ ์‹ค์ œ๋กœ innerGenerator๊ฐ€ ์‹คํ–‰๋˜์ง€๋Š” ์•Š๋Š”๋‹ค.

(yield-delegation doesn't even have to be directed to another generator; it can just be directed to a non-generator, general iterable.)


4.6 ใ€€ Generator Concurrency

yujo

  • ๋‹ค์Œ ์ฝ”๋“œ์—์„œ console์— true๊ฐ€ ์ถœ๋ ฅ๋˜๋Š” ๊ณณ์€ ์–ด๋””์ผ๊นŒ์š”?
const res = [];

function* foo() {
  var random = Math.random();

  yield;

  res.push(random);
}

const it = foo();

console.log(Boolean(res.length)); // (1)

it.next();

console.log(Boolean(res.length)); // (2)

it.next();

console.log(Boolean(res.length)); // (3)

it.next();

console.log(Boolean(res.length)); // (4)
๐Ÿ“„ ๋‹ต์ง€
(3), (4)

4.7 ใ€€ Thunks

yujo

  1. ๋น„๋™๊ธฐ ํŒจํ„ด์—์„œ Thunks๋ฅผ Promise ๋Œ€์‹  ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค. (O / X)
  2. Thunk๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.
๐Ÿ“„ ๋‹ต์ง€
1.X 

Thunk๋Š” Prmise์˜ ๋ฏฟ์Œ์„ฑ/์กฐํ•ฉ์„ฑ์„ ๋ณด์žฅํ•˜์ง€ ๋ชป ํ•œ๋‹ค.

2. ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์šด๋ช…์„ ๊ฐ€์ง„ ์ธ์ž๊ฐ€ ์—†๋Š” ํ•จ์ˆ˜, Thunk์˜ˆ์‹œ๋Š” ๋ฐ‘์˜ fooThunk()

function foo(x, y) {
  return x + y;
}

function fooThunk() {
  return foo(3, 4)
}

4.8 ใ€€ Pre-ES6 Generators

holee

  1. Generator์˜ ES5 polyfill์„ ์œ„ํ•œ ์œ ๋ช…ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘ facebook์ด ๋งŒ๋“  (___________)๊ฐ€ ์žˆ๋‹ค.

  2. ๋‹ค์Œ์€ Generator polyfill ์ฝ”๋“œ์˜ ์ผ๋ถ€์ด๋‹ค. ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ณ€์ˆ˜์˜ ๊ธฐ๋Šฅ์„ ์„ค๋ช…ํ•˜๋ผ.

function foo(url) {
	...
	return {
		next: function(v) {
			if (!__blank__) {
				__blank__ = 1;
				return {
					done: false,
					value: process()
				};
			}
			else if (__blank__ == 1) {
				__blank__ = 2;
				return {
					done: true,
					value: process( v )
				};
			}
		...
}
๐Ÿ“„ ๋‹ต์ง€
  1. Generator์˜ ES5 polyfill์„ ์œ„ํ•œ ์œ ๋ช…ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘ facebook์ด ๋งŒ๋“  (regenerator)๊ฐ€ ์žˆ๋‹ค.

  2. ๋‹ค์Œ์€ Generator polyfill ์ฝ”๋“œ์˜ ์ผ๋ถ€์ด๋‹ค. ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ณ€์ˆ˜์˜ ๊ธฐ๋Šฅ์„ ์„ค๋ช…ํ•˜๋ผ.

function foo(url) {
	// manage generator state
	var state;

	// generator-wide variable declarations
	var val;

	function process(v) {
		switch (state) {
			case 1:
				console.log( "requesting:", url );
				return request( url );
			case 2:
				val = v;
				console.log( val );
				return;
			case 3:
				var err = v;
				console.log( "Oops:", err );
				return false;
		}
	}

	// make and return an iterator
	return {
		next: function(v) {
			// initial state
			if (!state) {
				state = 1;
				return {
					done: false,
					value: process()
				};
			}
			// yield resumed successfully
			else if (state == 1) {
				state = 2;
				return {
					done: true,
					value: process( v )
				};
			}
			// generator already completed
			else {
				return {
					done: true,
					value: undefined
				};
			}
		},
		"throw": function(e) {
			// the only explicit error handling is in
			// state *1*
			if (state == 1) {
				state = 3;
				return {
					done: true,
					value: process( e )
				};
			}
			// otherwise, an error won't be handled,
			// so just throw it right back out
			else {
				throw e;
			}
		}
	};
}