ν‹°μŠ€ν† λ¦¬ λ·°

μ œλ„ˆλ ˆμ΄ν„°λž€?

ES6μ—μ„œ λ„μž…λœ μ œλ„ˆλ ˆμ΄ν„°(generator)λŠ” μ½”λ“œ λΈ”λ‘μ˜ 싀행을 μΌμ‹œ μ€‘μ§€ν–ˆλ‹€κ°€ ν•„μš”ν•œ μ‹œμ μ— μž¬κ°œν•  수 μžˆλŠ” νŠΉμˆ˜ν•œ ν•¨μˆ˜μž…λ‹ˆλ‹€. μ œλ„ˆλ ˆμ΄ν„°μ™€ 일반 ν•¨μˆ˜μ˜ μ°¨μ΄λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

 

1. μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” ν•¨μˆ˜ ν˜ΈμΆœμžμ—κ²Œ ν•¨μˆ˜ μ‹€ν–‰μ˜ μ œμ–΄κΆŒμ„ 양도할 수 μžˆλ‹€.

ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•œ 이후 ν•¨μˆ˜ 싀행을 μ œμ–΄ν•  수 μ—†λŠ” 일반 ν•¨μˆ˜μ™€ 달리 μ œλ„ˆλ ˆμ΄ν„°λŠ” ν•¨μˆ˜ ν˜ΈμΆœμžκ°€ ν•¨μˆ˜ 싀행을 μΌμ‹œ μ€‘μ§€μ‹œν‚€κ±°λ‚˜ μž¬κ°œμ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

 

2. μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” ν•¨μˆ˜ ν˜ΈμΆœμžμ™€ ν•¨μˆ˜μ˜ μƒνƒœλ₯Ό 주고받을 수 μžˆλ‹€.

ν•¨μˆ˜κ°€ μ‹€ν–‰λ˜κ³  μžˆλŠ” λ™μ•ˆ ν•¨μˆ˜ μ™ΈλΆ€μ—μ„œ ν•¨μˆ˜ λ‚΄λΆ€λ‘œ 값을 μ „λ‹¬ν•˜μ—¬ ν•¨μˆ˜μ˜ μƒνƒœλ₯Ό λ³€κ²½ν•  수 μ—†λŠ” 일반 ν•¨μˆ˜μ™€ 달리 μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” ν•¨μˆ˜ ν˜ΈμΆœμžμ™€ μ–‘λ°©ν–₯으둜 ν•¨μˆ˜μ˜ μƒνƒœλ₯Ό 주고받을 수 μžˆμŠ΅λ‹ˆλ‹€.

 

3. μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ μ œλ„ˆλ ˆμ΄ν„° 객체λ₯Ό λ°˜ν™˜ν•œλ‹€.

일반 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ ν•¨μˆ˜ μ½”λ“œλ₯Ό 일괄 μ‹€ν–‰ν•˜κ³  값을 λ°˜ν™˜λ°›μ§€λ§Œ μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ ν•¨μˆ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜λŠ” 것이 μ•„λ‹ˆλΌ μ΄ν„°λŸ¬λΈ”μ΄λ©΄μ„œ λ™μ‹œμ— μ΄ν„°λ ˆμ΄ν„°μΈ μ œλ„ˆλ ˆμ΄ν„° 객체λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.


μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜μ˜ μ •μ˜

μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” function* ν‚€μ›Œλ“œλ‘œ μ„ μ–Έν•˜λ©° ν•˜λ‚˜ μ΄μƒμ˜ yield ν‘œν˜„μ‹μ„ ν¬ν•¨ν•©λ‹ˆλ‹€. μ• μŠ€ν„°λ¦¬μŠ€ν¬(*)의 μœ„μΉ˜λŠ” function ν‚€μ›Œλ“œμ™€ ν•¨μˆ˜ 이름 사이 μ–΄λ””λ“  μƒκ΄€μ—†μ§€λ§Œ function ν‚€μ›Œλ“œ λ°”λ‘œ 뒀에 λΆ™μ΄λŠ” 것을 ꢌμž₯ν•©λ‹ˆλ‹€.

 

// μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜ μ„ μ–Έλ¬Έ
function* genDecFunc() {
  yield 1;
}

// μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜ ν‘œν˜„μ‹
const genExpFunc = function* () {
  yield 1;
};

// μ œλ„ˆλ ˆμ΄ν„° λ©”μ„œλ“œ
const obj = {
  * genObjMethod() {
    yield 1;
  }
};

// μ œλ„ˆλ ˆμ΄ν„° 클래슀 λ©”μ„œλ“œ
class MyClass {
  * genClsMethod() {
    yield 1;
  }
}

 

μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” ν™”μ‚΄ν‘œ ν•¨μˆ˜λ‘œ μ •μ˜ν•  수 μ—†κ³  new μ—°μ‚°μžμ™€ ν•¨κ»˜ μƒμ„±μž ν•¨μˆ˜λ‘œ ν˜ΈμΆœν•  수 μ—†μŠ΅λ‹ˆλ‹€.

 

const genArrowFunc = * () => {
  yield 1;
}; // SyntaxError: Unexpected token '*'

function* genFunc() {
  yield 1;
}

new genFunc(); // TypeError: genFunc is not a constructor

μ œλ„ˆλ ˆμ΄ν„° 객체

μ œλ„ˆν…Œμ΄ν„° ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ μ΄ν„°λŸ¬λΈ”μ΄λ©΄μ„œ λ™μ‹œμ— μ΄ν„°λ ˆμ΄ν„°μΈ μ œλ„ˆλ ˆμ΄ν„° 객체λ₯Ό 생성해 λ°˜ν™˜ν•©λ‹ˆλ‹€.

 

즉, μ œλ„ˆλ ˆμ΄ν„° κ°μ²΄λŠ” Symbol.iterator λ©”μ„œλ“œλ₯Ό μƒμ†λ°›λŠ” μ΄ν„°λŸ¬λΈ”μ΄λ©΄μ„œ, value, done ν”„λ‘œνΌν‹°λ₯Ό κ°–λŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” next λ©”μ„œλ“œλ₯Ό μ†Œμœ ν•˜λŠ” μ΄ν„°λ ˆμ΄ν„°μž…λ‹ˆλ‹€. λ”°λΌμ„œ Symbol.iterator λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•΄μ„œ λ³„λ„λ‘œ μ΄ν„°λ ˆμ΄ν„°λ₯Ό 생성할 ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.

 

// μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜
function* genFunc() {
  yield 1;
  yield 2;
  yield 3;
}

// μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ μ œλ„ˆλ ˆμ΄ν„° 객체λ₯Ό λ°˜ν™˜ν•œλ‹€.
const generator = genFunc();

// μ œλ„ˆλ ˆμ΄ν„° κ°μ²΄λŠ” μ΄ν„°λŸ¬λΈ”μ΄λ©΄μ„œ λ™μ‹œμ— μ΄ν„°λ ˆμ΄ν„°λ‹€.
// μ΄ν„°λŸ¬λΈ”μ€ Symbol.iterator λ©”μ„œλ“œλ₯Ό 직접 κ΅¬ν˜„ν•˜κ±°λ‚˜ ν”„λ‘œν† νƒ€μž… 체인을 톡해 상속받은 객체닀.
console.log(Symbol.iterator in generator); // true
// μ΄ν„°λ ˆμ΄ν„°λŠ” next λ©”μ„œλ“œλ₯Ό κ°–λŠ”λ‹€.
console.log('next' in generator); // true

 

μ œλ„ˆλ ˆμ΄ν„° κ°μ²΄λŠ” next λ©”μ„œλ“œ 외에 μ΄ν„°λ ˆμ΄ν„°μ— μ—†λŠ” return, throw λ©”μ„œλ“œλ₯Ό μΆ”κ°€λ‘œ κ°–μŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ μ œλ„ˆλ ˆμ΄ν„° 객체의 μ„Έ 개의 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ λ‹€μŒκ³Ό 같이 λ™μž‘ν•©λ‹ˆλ‹€.

  • next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜μ˜ yield ν‘œν˜„μ‹κΉŒμ§€ μ½”λ“œ 블둝을 μ‹€ν–‰ν•˜κ³  yield된 값을 value ν”„λ‘œνΌν‹° κ°’μœΌλ‘œ, falseλ₯Ό done ν”„λ‘œνΌν‹° κ°’μœΌλ‘œ κ°–λŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜
  • return λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ 인수둜 전달받은 값을 value ν”„λ‘œνΌν‹° κ°’μœΌλ‘œ, trueλ₯Ό done ν”„λ‘œνΌν‹° κ°’μœΌλ‘œ κ°–λŠ” μ΄λŸ¬ν…Œμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜
  • throw λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ 인수둜 전달받은 μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€κ³  undefinedλ₯Ό value ν”„λ‘œνΌν‹° κ°’μœΌλ‘œ, trueλ₯Ό done ν”„λ‘œνΌν‹° κ°’μœΌλ‘œ κ°–λŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜
function* genFunc() {
  try {
    yield 1;
    yield 2;
    yield 3;
  } catch (e) {
    console.error(e);
  }
}

const generator = genFunc();

console.log(generator.next()); // {value: 1, done: false}
console.log(generator.return('End!')); // {value: "End!", done: true}
console.log(generator.throw('Error!')); // {value: undefined, done: true}

μ œλ„ˆλ ˆμ΄ν„°μ˜ μΌμ‹œ 쀑지와 재개

μ œλ„ˆλ ˆμ΄ν„°λŠ” ν•¨μˆ˜ ν˜ΈμΆœμžμ—κ²Œ μ œμ–΄κΆŒμ„ μ–‘λ„ν•˜μ—¬ yield ν‚€μ›Œλ“œμ™€ next λ©”μ„œλ“œλ₯Ό 톡해 싀행을 μΌμ‹œ μ€‘μ§€ν•˜κ³  ν•„μš”ν•œ μ‹œμ μ— ν•¨μˆ˜ 싀행을 μž¬κ°œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

yield ν‚€μ›Œλ“œλŠ” μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜μ˜ 싀행을 μΌμ‹œ μ€‘μ‹œμ‹œν‚€κ±°λ‚˜ yield ν‚€μ›Œλ“œ 뒀에 μ˜€λŠ” ν‘œν˜„μ‹μ˜ 평가 κ²°κ³Όλ₯Ό μ œλ„ˆλ ˆμ΄ν„°

ν•¨μˆ˜ ν˜ΈμΆœμžμ—κ²Œ λ°˜ν™˜ν•©λ‹ˆλ‹€.

 

// μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜
function* genFunc() {
  yield 1;
  yield 2;
  yield 3;
}

// μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ μ œλ„ˆλ ˆμ΄ν„° 객체λ₯Ό λ°˜ν™˜ν•œλ‹€.
// μ΄ν„°λŸ¬λΈ”μ΄λ©΄μ„œ λ™μ‹œμ— μ΄ν„°λ ˆμ΄ν„°μΈ μ œλ„ˆλ ˆμ΄ν„° κ°μ²΄λŠ” next λ©”μ„œλ“œλ₯Ό κ°–λŠ”λ‹€.
const generator = genFunc();

// 처음 next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ 첫 번째 yield ν‘œν˜„μ‹κΉŒμ§€ μ‹€ν–‰λ˜κ³  μΌμ‹œ μ€‘μ§€λœλ‹€.
// next λ©”μ„œλ“œλŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체({value, done})λ₯Ό λ°˜ν™˜ν•œλ‹€.
// value ν”„λ‘œνΌν‹°μ—λŠ” 첫 번째 yield ν‘œν˜„μ‹μ—μ„œ yield된 κ°’ 1이 ν• λ‹Ήλœλ‹€.
// done ν”„λ‘œνΌν‹°μ—λŠ” μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜κ°€ λκΉŒμ§€ μ‹€ν–‰λ˜μ—ˆλŠ”μ§€λ₯Ό λ‚˜νƒ€λ‚΄λŠ” falseκ°€ ν• λ‹Ήλœλ‹€.
console.log(generator.next()); // {value: 1, done: false}

// λ‹€μ‹œ next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ 두 번째 yield ν‘œν˜„μ‹κΉŒμ§€ μ‹€ν–‰λ˜κ³  μΌμ‹œ μ€‘μ§€λœλ‹€.
// next λ©”μ„œλ“œλŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체({value, done})λ₯Ό λ°˜ν™˜ν•œλ‹€.
// value ν”„λ‘œνΌν‹°μ—λŠ” 두 번째 yield ν‘œν˜„μ‹μ—μ„œ yield된 κ°’ 2κ°€ ν• λ‹Ήλœλ‹€.
// done ν”„λ‘œνΌν‹°μ—λŠ” μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜κ°€ λκΉŒμ§€ μ‹€ν–‰λ˜μ—ˆλŠ”μ§€λ₯Ό λ‚˜νƒ€λ‚΄λŠ” falseκ°€ ν• λ‹Ήλœλ‹€.
console.log(generator.next()); // {value: 2, done: false}

// λ‹€μ‹œ next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μ„Έ 번째 yield ν‘œν˜„μ‹κΉŒμ§€ μ‹€ν–‰λ˜κ³  μΌμ‹œ μ€‘μ§€λœλ‹€.
// next λ©”μ„œλ“œλŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체({value, done})λ₯Ό λ°˜ν™˜ν•œλ‹€.
// value ν”„λ‘œνΌν‹°μ—λŠ” μ„Έ 번째 yield ν‘œν˜„μ‹μ—μ„œ yield된 κ°’ 3이 ν• λ‹Ήλœλ‹€.
// done ν”„λ‘œνΌν‹°μ—λŠ” μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜κ°€ λκΉŒμ§€ μ‹€ν–‰λ˜μ—ˆλŠ”μ§€λ₯Ό λ‚˜νƒ€λ‚΄λŠ” falseκ°€ ν• λ‹Ήλœλ‹€.
console.log(generator.next()); // {value: 3, done: false}

// λ‹€μ‹œ next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ 남은 yield ν‘œν˜„μ‹μ΄ μ—†μœΌλ―€λ‘œ μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜μ˜ λ§ˆμ§€λ§‰κΉŒμ§€ μ‹€ν–‰ν•œλ‹€.
// next λ©”μ„œλ“œλŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체({value, done})λ₯Ό λ°˜ν™˜ν•œλ‹€.
// value ν”„λ‘œνΌν‹°μ—λŠ” μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜μ˜ λ°˜ν™˜κ°’ undefinedκ°€ ν• λ‹Ήλœλ‹€.
// done ν”„λ‘œνΌν‹°μ—λŠ” μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜κ°€ λκΉŒμ§€ μ‹€ν–‰λ˜μ—ˆμŒμ„ λ‚˜νƒ€λ‚΄λŠ” trueκ°€ ν• λ‹Ήλœλ‹€.
console.log(generator.next()); // {value: undefined, done: true}
  1. μ œλ„ˆλ ˆμ΄ν„° 객체의 next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ yield ν‘œν˜„μ‹κΉŒμ§€ μ‹€ν–‰λ˜κ³  μΌμ‹œ 쀑지(suspend)되고 ν•¨μˆ˜ μ œμ–΄κΆŒμ΄ 호좜자둜 양도
  2. μ œλ„ˆλ ˆμ΄ν„° 객체의 next λ©”μ„œλ“œλŠ” value, done ν”„λ‘œνΌν‹°λ₯Ό κ°–λŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜
  3. value ν”„λ‘œνΌν‹°μ—λŠ” yield의 κ°’, done ν”„λ‘œνΌν‹°μ—λŠ” ν•¨μˆ˜κ°€ λκΉŒμ§€ μ‹€ν–‰λ˜μ—ˆλŠ”μ§€λ₯Ό λ‚˜νƒ€λ‚΄λŠ” λΆˆλ¦¬μ–Έ 값이 ν• λ‹Ή
generator.next() -> yield -> generator.next() -> yield -> ... -> generator.next() -> return

 

이처럼 next λ©”μ„œλ“œλ₯Ό 반볡 ν˜ΈμΆœν•˜μ—¬ yield ν‘œν˜„μ‹κΉŒμ§€ μ‹€ν–‰κ³Ό μΌμ‹œ 쀑지λ₯Ό λ°˜λ³΅ν•˜λ‹€κ°€ μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜κ°€ λκΉŒμ§€ μ‹€ν–‰λ˜λ©΄ next λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•˜λŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체의 value ν”„λ‘œνΌν‹°μ™€ done ν”„λ‘œνΌν‹°μ—λŠ” μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜μ˜ λ°˜ν™˜κ°’κ³Ό λκΉŒμ§€ μ‹€ν–‰λ˜μ—ˆμŒμ„ λ‚˜νƒ€λ‚΄λŠ” trueκ°€ ν• λ‹Ήλ©λ‹ˆλ‹€.

 

 

λ˜ν•œ μ œλ„ˆλ ˆμ΄ν„° 객체의 next λ©”μ„œλ“œμ— μ „λ‹¬ν•œ μΈμˆ˜λŠ” μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜μ˜ yield ν‘œν˜„μ‹μ„ ν• λ‹Ήλ°›λŠ” λ³€μˆ˜μ— ν• λ‹Ήλ˜μ–΄ ν•¨μˆ˜ ν˜ΈμΆœμžμ™€ ν•¨μˆ˜μ˜ μƒνƒœλ₯Ό 주고받을 수 μžˆμŠ΅λ‹ˆλ‹€.

 

function* genFunc() {
  // 처음 next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ 첫 번째 yield ν‘œν˜„μ‹κΉŒμ§€ μ‹€ν–‰λ˜κ³  μΌμ‹œ μ€‘μ§€λœλ‹€.
  // μ΄λ•Œ yield된 κ°’ 1은 next λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•œ μ΄ν„°λ ˆμ΄ν„° 리절트 객체의 value ν”„λ‘œνΌν‹°μ— ν• λ‹Ήλœλ‹€.
  // x λ³€μˆ˜μ—λŠ” 아직 아무것도 ν• λ‹Ήλ˜μ§€ μ•Šμ•˜λ‹€. x λ³€μˆ˜μ˜ 값은 next λ©”μ„œλ“œκ°€ 두 번째 호좜될 λ•Œ κ²°μ •λœλ‹€.
  const x = yield 1;

  // 두 번째 next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  λ•Œ μ „λ‹¬ν•œ 인수 10은 첫 번째 yield ν‘œν˜„μ‹μ„ ν• λ‹Ήλ°›λŠ” x λ³€μˆ˜μ— ν• λ‹Ήλœλ‹€.
  // 즉, const x = yield 1;은 두 번째 next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν–ˆμ„ λ•Œ μ™„λ£Œλœλ‹€.
  // 두 번째 next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ 두 번째 yield ν‘œν˜„μ‹κΉŒμ§€ μ‹€ν–‰λ˜κ³  μΌμ‹œ μ€‘μ§€λœλ‹€.
  // μ΄λ•Œ yield된 κ°’ x + 10은 next λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•œ μ΄ν„°λ ˆμ΄ν„° 리절트 객체의 value ν”„λ‘œνΌν‹°μ— ν• λ‹Ήλœλ‹€.
  const y = yield (x + 10);

  // μ„Έ 번째 next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  λ•Œ μ „λ‹¬ν•œ 인수 20은 두 번째 yield ν‘œν˜„μ‹μ„ ν• λ‹Ήλ°›λŠ” y λ³€μˆ˜μ— ν• λ‹Ήλœλ‹€.
  // 즉, const y = yield (x + 10);λŠ” μ„Έ 번째 next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν–ˆμ„ λ•Œ μ™„λ£Œλœλ‹€.
  // μ„Έ 번째 next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ ν•¨μˆ˜ λκΉŒμ§€ μ‹€ν–‰λœλ‹€.
  // μ΄λ•Œ μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜μ˜ λ°˜ν™˜κ°’ x + yλŠ” next λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•œ μ΄ν„°λ ˆμ΄ν„° 리절트 객체의 value ν”„λ‘œνΌν‹°μ— ν• λ‹Ήλœλ‹€.
  // 일반적으둜 μ œλ„ˆλ ˆμ΄ν„°μ˜ λ°˜ν™˜κ°’μ€ μ˜λ―Έκ°€ μ—†λ‹€.
  // λ”°λΌμ„œ μ œλ„ˆλ ˆμ΄ν„°μ—μ„œλŠ” 값을 λ°˜ν™˜ν•  ν•„μš”κ°€ μ—†κ³  return은 μ’…λ£Œμ˜ 의미둜만 μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.
  return x + y;
}

// μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ μ œλ„ˆλ ˆμ΄ν„° 객체λ₯Ό λ°˜ν™˜ν•œλ‹€.
// μ΄ν„°λŸ¬λΈ”μ΄λ©° λ™μ‹œμ— μ΄ν„°λ ˆμ΄ν„°μΈ μ œλ„ˆλ ˆμ΄ν„° κ°μ²΄λŠ” next λ©”μ„œλ“œλ₯Ό κ°–λŠ”λ‹€.
const generator = genFunc(0);

// 처음 ν˜ΈμΆœν•˜λŠ” next λ©”μ„œλ“œμ—λŠ” 인수λ₯Ό μ „λ‹¬ν•˜μ§€ μ•ŠλŠ”λ‹€.
// λ§Œμ•½ 처음 ν˜ΈμΆœν•˜λŠ” next λ©”μ„œλ“œμ— 인수λ₯Ό μ „λ‹¬ν•˜λ©΄ λ¬΄μ‹œλœλ‹€.
// next λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•œ μ΄ν„°λ ˆμ΄ν„° 리절트 객체의 value ν”„λ‘œνΌν‹°μ—λŠ” 첫 번째 yield된 κ°’ 1이 ν• λ‹Ήλœλ‹€.
let res = generator.next();
console.log(res); // {value: 1, done: false}

// next λ©”μ„œλ“œμ— 인수둜 μ „λ‹¬ν•œ 10은 genFunc ν•¨μˆ˜μ˜ x λ³€μˆ˜μ— ν• λ‹Ήλœλ‹€.
// next λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•œ μ΄ν„°λ ˆμ΄ν„° 리절트 객체의 value ν”„λ‘œνΌν‹°μ—λŠ” 두 번째 yield된 κ°’ 20이 ν• λ‹Ήλœλ‹€.
res = generator.next(10);
console.log(res); // {value: 20, done: false}

// next λ©”μ„œλ“œμ— 인수둜 μ „λ‹¬ν•œ 20은 genFunc ν•¨μˆ˜μ˜ y λ³€μˆ˜μ— ν• λ‹Ήλœλ‹€.
// next λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•œ μ΄ν„°λ ˆμ΄ν„° 리절트 객체의 value ν”„λ‘œνΌν‹°μ—λŠ” μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜μ˜ λ°˜ν™˜κ°’ 30이 ν• λ‹Ήλœλ‹€.
res = generator.next(20);
console.log(res); // {value: 30, done: true}

 

이처럼 ν•¨μˆ˜ ν˜ΈμΆœμžλŠ” next λ©”μ„œλ“œλ₯Ό 톡해 yield ν‘œν˜„μ‹κΉŒμ§€ ν•¨μˆ˜λ₯Ό μ‹€ν–‰μ‹œμΌœ μ œλ„ˆλ ˆμ΄ν„° 객체가 κ΄€λ¦¬ν•˜λŠ” μƒνƒœκ°’μ„ κΊΌλ‚΄μ˜¬ 수 있고, next λ©”μ„œλ“œμ— 인수λ₯Ό 전달해 μ œλ„ˆλ ˆμ΄ν„° 객체에 μƒνƒœλ₯Ό 밀어넣을 수 μžˆμŠ΅λ‹ˆλ‹€.

 

μ΄λŸ¬ν•œ μ œλ„ˆλ ˆμ΄ν„°μ˜ νŠΉμ„±μ„ ν™œμš©ν•˜λ©΄ 비동기 처리λ₯Ό 동기 처리처럼 κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.


μ œλ„ˆλ ˆμ΄ν„°μ˜ ν™œμš©

μ΄ν„°λŸ¬λΈ”μ˜ κ΅¬ν˜„

μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ μ΄ν„°λ ˆμ΄μ…˜ ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•΄ μ΄ν„°λŸ¬λΈ”μ„ μƒμ„±ν•˜λŠ” 방식보닀 κ°„λ‹¨νžˆ μ΄ν„°λŸ¬λΈ”μ„ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 

 

// 1. λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”μ„ μƒμ„±ν•˜λŠ” ν•¨μˆ˜
const infiniteFibonacci = (function () {
  let [pre, cur] = [0, 1];

  return {
    [Symbol.iterator]() { return this; },
    next() {
      [pre, cur] = [cur, pre + cur];
      // λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”μ΄λ―€λ‘œ done ν”„λ‘œνΌν‹°λ₯Ό μƒλž΅ν•œλ‹€.
      return { value: cur };
    }
  };
}());

// infiniteFibonacciλŠ” λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”μ΄λ‹€.
for (const num of infiniteFibonacci) {
  if (num > 10000) break;
  console.log(num); // 1 2 3 5 8...2584 4181 6765
}


// 2. λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”μ„ μƒμ„±ν•˜λŠ” μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜
const infiniteFibonacci = (function* () {
  let [pre, cur] = [0, 1];

  while (true) {
    [pre, cur] = [cur, pre + cur];
    yield cur;
  }
}());

// infiniteFibonacciλŠ” λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”μ΄λ‹€.
for (const num of infiniteFibonacci) {
  if (num > 10000) break;
  console.log(num); // 1 2 3 5 8...2584 4181 6765
}

 

비동기 처리

μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” next λ©”μ„œλ“œμ™€ yield ν‘œν˜„μ‹μ„ 톡해 ν•¨μˆ˜ ν˜ΈμΆœμžμ™€ ν•¨μˆ˜μ˜ μƒνƒœλ₯Ό 주고받을 수 있기 λ•Œλ¬Έμ— ν”„λ‘œλ―ΈμŠ€λ₯Ό μ‚¬μš©ν•œ 비동기 처리λ₯Ό 동기 처리처럼 κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 즉, ν”„λ‘œλ―ΈμŠ€μ˜ 후속 처리 λ©”μ„œλ“œ then/catch/finally 없이 비동기 처리 κ²°κ³Όλ₯Ό λ°˜ν™˜ν•˜λ„λ‘ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

// node-fetchλŠ” node.js ν™˜κ²½μ—μ„œ window.fetch ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•œ νŒ¨ν‚€μ§€λ‹€.
// λΈŒλΌμš°μ € ν™˜κ²½μ—μ„œ 이 예제λ₯Ό μ‹€ν–‰ν•œλ‹€λ©΄ μ•„λž˜ μ½”λ“œλŠ” ν•„μš” μ—†λ‹€.
// https://github.com/node-fetch/node-fetch
const fetch = require('node-fetch');

// μ œλ„ˆλ ˆμ΄ν„° μ‹€ν–‰κΈ°
const async = generatorFunc => {
  const generator = generatorFunc(); // β‘‘

  const onResolved = arg => {
    const result = generator.next(arg); // β‘€

    return result.done
      ? result.value // ⑨
      : result.value.then(res => onResolved(res)); // ⑦
  };

  return onResolved; // β‘’
};

(async(function* fetchTodo() { // β‘ 
  const url = 'https://jsonplaceholder.typicode.com/todos/1';

  const response = yield fetch(url); // β‘₯
  const todo = yield response.json(); // ⑧
  console.log(todo);
  // {userId: 1, id: 1, title: 'delectus aut autem', completed: false}
})()); // β‘£

 

async/await을 μ‚¬μš©ν•˜λ©΄ μœ„ 예제의 async ν•¨μˆ˜μ™€ 같은 μ œλ„ˆλ ˆμ΄ν„° μ‹€ν–‰κΈ°λ₯Ό μ‚¬μš©ν•  ν•„μš”λŠ” μ—†μ§€λ§Œ ν•„μš”ν•˜λ‹€λ©΄ co 라이브러리λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 ꢌμž₯λ©λ‹ˆλ‹€.

 

const fetch = require('node-fetch');
// https://github.com/tj/co
const co = require('co');

co(function* fetchTodo() {
  const url = 'https://jsonplaceholder.typicode.com/todos/1';

  const response = yield fetch(url);
  const todo = yield response.json();
  console.log(todo);
  // { userId: 1, id: 1, title: 'delectus aut autem', completed: false }
});

async/await

ES8μ—μ„œ μ œλ„ˆλ ˆμ΄ν„°λ³΄λ‹€ κ°„λ‹¨ν•˜κ³  가독성 μ’‹κ²Œ 비동기 처리λ₯Ό 동기 처리처럼 λ™μž‘ν•˜λ„λ‘ κ΅¬ν˜„ν•  수 μžˆλŠ” async/awaitκ°€ λ„μž…λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

  • async/awaitλŠ” ν”„λ‘œλ―ΈμŠ€λ₯Ό 기반으둜 λ™μž‘
  • async/await을 μ‚¬μš©ν•˜λ©΄ 비동기 처리λ₯Ό 후속 μ²˜λ¦¬ν•  ν•„μš” 없이 마치 동기 처리처럼 ν”„λ‘œλ―ΈμŠ€κ°€ κ²°κ³Όλ₯Ό λ°˜ν™˜
const fetch = require('node-fetch');

async function fetchTodo() {
  const url = 'https://jsonplaceholder.typicode.com/todos/1';

  const response = await fetch(url);
  const todo = await response.json();
  console.log(todo);
  // {userId: 1, id: 1, title: 'delectus aut autem', completed: false}
}

fetchTodo();

 

async ν•¨μˆ˜

async ν•¨μˆ˜λŠ” async ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄ μ •μ˜ν•˜λ©° μ–Έμ œλ‚˜ ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. async ν•¨μˆ˜κ°€ λͺ…μ‹œμ μœΌλ‘œ ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•˜μ§€ μ•Šλ”λΌλ„ async ν•¨μˆ˜λŠ” μ•”λ¬΅μ μœΌλ‘œ λ°˜ν™˜κ°’μ„ resolveν•˜λŠ” ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. λ˜ν•œ, await ν‚€μ›Œλ“œλŠ” λ°˜λ“œμ‹œ async ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

 

// async ν•¨μˆ˜ μ„ μ–Έλ¬Έ
async function foo(n) { return n; }
foo(1).then(v => console.log(v)); // 1

// async ν•¨μˆ˜ ν‘œν˜„μ‹
const bar = async function (n) { return n; };
bar(2).then(v => console.log(v)); // 2

// async ν™”μ‚΄ν‘œ ν•¨μˆ˜
const baz = async n => n;
baz(3).then(v => console.log(v)); // 3

// async λ©”μ„œλ“œ
const obj = {
  async foo(n) { return n; }
};
obj.foo(4).then(v => console.log(v)); // 4

// async 클래슀 λ©”μ„œλ“œ
class MyClass {
  // async constructor() { } => SyntaxError: Class constructor may not be an async method
  async bar(n) { return n; }
}
const myClass = new MyClass();
myClass.bar(5).then(v => console.log(v)); // 5

*클래슀의 constructor λ©”μ„œλ“œλŠ” μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•΄μ•Ό ν•˜μ§€λ§Œ async ν•¨μˆ˜λŠ” μ–Έμ œλ‚˜ ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ— constructor λ©”μ„œλ“œλŠ” async λ©”μ„œλ“œκ°€ 될 수 μ—†μŒ

 

await ν‚€μ›Œλ“œ

await ν‚€μ›Œλ“œλŠ” ν”„λ‘œλ―ΈμŠ€κ°€ settled μƒνƒœκ°€ 될 λ•ŒκΉŒμ§€ λŒ€κΈ°ν•˜λ‹€κ°€ settled μƒνƒœκ°€ 되면 ν”„λ‘œλ―ΈμŠ€κ°€ resolveν•œ 처리 κ²°κ³Όλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. await ν‚€μ›Œλ“œλŠ” λ°˜λ“œμ‹œ ν”„λ‘œλ―ΈμŠ€ μ•žμ—μ„œ μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

 

const fetch = require('node-fetch');

const getGithubUserName = async id => {
  const res = await fetch(`https://api.github.com/users/${id}`); // β‘ 
  const { name } = await res.json(); // β‘‘
  console.log(name); // Ungmo Lee
};

getGithubUserName('ungmo2');
  • fetch ν•¨μˆ˜κ°€ μˆ˜ν–‰ν•œ HTTP μš”μ²­μ— λŒ€ν•œ μ„œλ²„μ˜ 응닡이 λ„μ°©ν•΄μ„œ fetch ν•¨μˆ˜κ°€ λ°˜ν™˜ν•œ ν”„λ‘œλ―ΈμŠ€ settled μƒνƒœκ°€ 될 λ•ŒκΉŒμ§€ λŒ€κΈ°ν•˜λ‹€κ°€ 이후 ν”„λ‘œλ―ΈμŠ€κ°€ settled μƒνƒœκ°€ 되면 ν”„λ‘œλ―ΈμŠ€κ°€ resolveν•œ 처리 κ²°κ³Όκ°€ res λ³€μˆ˜μ— ν• λ‹Ή

이처럼 await ν‚€μ›Œλ“œλŠ” λ‹€μŒ 싀행을 μΌμ‹œ μ€‘μ‹œμ‹œμΌ°λ‹€κ°€ ν”„λ‘œλ―ΈμŠ€κ°€ settled μƒνƒœκ°€ 되면 λ‹€μ‹œ μž¬κ°œν•©λ‹ˆλ‹€. λ”°λΌμ„œ μ•žμ„  비동기 처리의 κ²°κ³Όλ₯Ό 가지고 λ‹€μŒ 비동기 처리λ₯Ό μˆ˜ν–‰ν•˜λŠ” μƒν™©μ²˜λŸΌ 처리 μˆœμ„œκ°€ 보μž₯λ˜μ–΄μ•Ό ν• λ•Œ λͺ¨λ“  ν”„λ‘œλ―ΈμŠ€μ— await ν‚€μ›Œλ“œλ₯Ό μ¨μ„œ 순차적으둜 μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

μ—λŸ¬ 처리

ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•˜λŠ” 비동기 ν•¨μˆ˜λŠ” λͺ…μ‹œμ μœΌλ‘œ 호좜될 수 있기 λ•Œλ¬Έμ— ν˜ΈμΆœμžκ°€ λͺ…ν™•ν•©λ‹ˆλ‹€. λ”°λΌμ„œ 호좜자 λ°©ν–₯을 μ „νŒŒλ˜λŠ” μ—λŸ¬λ₯Ό async/awaitμ—μ„œ try...catch문을 μ‚¬μš©ν•΄ μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

const fetch = require('node-fetch');

const foo = async () => {
  try {
    const wrongUrl = 'https://wrong.url';

    const response = await fetch(wrongUrl);
    const data = await response.json();
    console.log(data);
  } catch (err) {
    console.error(err); // TypeError: Failed to fetch
  }
};

foo();

 

  • foo ν•¨μˆ˜μ˜ catch 문은 HTTP ν†΅μ‹ μ—μ„œ λ°œμƒν•œ λ„€νŠΈμ›Œν¬ μ—λŸ¬λΏ μ•„λ‹ˆλΌ try μ½”λ“œ 블둝 λ‚΄μ˜ λͺ¨λ“  λ¬Έμ—μ„œ λ°œμƒν•œ 일반적인 μ—λŸ¬κΉŒμ§€ λͺ¨λ‘ 캐치

이처럼 async ν•¨μˆ˜ λ‚΄μ—μ„œ catch 문을 μ‚¬μš©ν•΄μ„œ μ—λŸ¬ 처리λ₯Ό ν•˜μ§€ μ•ŠμœΌλ©΄ async ν•¨μˆ˜λŠ” λ°œμƒν•œ μ—λŸ¬λ₯Ό rejectν•˜λŠ” ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•˜κΈ° λ•Œλ¬Έμ— Promise.prototype.catch 후속 처리 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

 

const fetch = require('node-fetch');

const foo = async () => {
  const wrongUrl = 'https://wrong.url';

  const response = await fetch(wrongUrl);
  const data = await response.json();
  return data;
};

foo()
  .then(console.log)
  .catch(console.error); // TypeError: Failed to fetch

[좜처] λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive

https://wikibook.co.kr/mjs/

 

λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive: μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ κΈ°λ³Έ κ°œλ…κ³Ό λ™μž‘ 원리

269개의 κ·Έλ¦Όκ³Ό 원리λ₯Ό νŒŒν—€μΉ˜λŠ” μ„€λͺ…μœΌλ‘œ ‘μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ κΈ°λ³Έ κ°œλ…κ³Ό λ™μž‘ 원리’λ₯Ό μ΄ν•΄ν•˜μž! μ›ΉνŽ˜μ΄μ§€μ˜ λ‹¨μˆœν•œ 보쑰 κΈ°λŠ₯을 μ²˜λ¦¬ν•˜κΈ° μœ„ν•œ μ œν•œμ μΈ μš©λ„λ‘œ νƒœμ–΄λ‚œ μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” 과도

wikibook.co.kr

'JavaScript > λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[JavaScript] λͺ¨λ“ˆ  (1) 2022.08.20
[JavaScript] μ—λŸ¬ 처리  (0) 2022.08.19
[JavaScript] ν”„λ‘œλ―ΈμŠ€(Promise)  (0) 2022.08.17
[JavaScript] REST API  (0) 2022.08.16
[JavaScript] Ajax  (0) 2022.08.15