[JS] μ œλ„ˆλ ˆμ΄ν„°μ™€ async/await

2025. 10. 21. 00:39Β·πŸ’› Frontend/πŸ’› Frontend : JavaScript
728x90

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

μ½”λ“œ λΈ”λ‘μ˜ 싀행을 μΌμ‹œ μ€‘μ§€ν–ˆλ‹€κ°€ ν•„μš”ν•œ μ‹œμ μ— μž¬κ°œν•  수 μžˆλŠ” νŠΉμˆ˜ν•œ ν•¨μˆ˜

  • function* 둜 μ •μ˜ν•œ ν•¨μˆ˜.
  • ν˜ΈμΆœν•˜λ©΄ λ°”λ‘œ μ‹€ν–‰λ˜μ§€ μ•Šκ³  “μ œλ„ˆλ ˆμ΄ν„° 객체(μ΄ν„°λ ˆμ΄ν„°)”λ₯Ό λ°˜ν™˜.
  • 이 κ°μ²΄μ—λŠ” next(), return(), throw() λ©”μ„œλ“œκ°€ 있고,
  • yield μ§€μ μ—μ„œ 싀행이 μΌμ‹œμ€‘μ§€/μž¬κ°œλœλ‹€.
  • next()λ₯Ό ν˜ΈμΆœν•  λ•Œλ§ˆλ‹€ λ‹€μŒ yieldκΉŒμ§€ μ§„ν–‰λœλ‹€.

 

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

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

 

일반 ν•¨μˆ˜λŠ” ν˜ΈμΆœν•˜λ©΄ μ œμ–΄κΆŒμ΄ ν•¨μˆ˜μ—κ²Œ λ„˜μ–΄κ°€κ³ , ν•¨μˆ˜κ°€ 호좜된 이후 ν•¨μˆ˜ 싀행을 μ œμ–΄ν•  수 μ—†λ‹€ → ν•¨μˆ˜ λ°–μ—μ„œ μ‹€ν–‰ 쀑인 ν•¨μˆ˜λ₯Ό λ©ˆμΆ”κ±°λ‚˜ μž¬κ°œν•  수 μ—†λ‹€

μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” ν•¨μˆ˜ ν˜ΈμΆœμžκ°€ ν•¨μˆ˜ 싀행을 μΌμ‹œ μ€‘μ§€μ‹œν‚€κ±°λ‚˜ μž¬κ°œμ‹œν‚¬ 수 μžˆλ‹€.

function* steps() {
  console.log('A');          // μ‹œμž‘
  yield 1;                   // ⟡ μ—¬κΈ°μ„œ μΌμ‹œμ€‘μ§€ (κ°’ 1을 λ°–μœΌλ‘œ 보냄)
  console.log('B');          // 재개되면 μ—¬κΈ°λΆ€ν„°
  yield 2;                   // ⟡ 또 쀑지 (κ°’ 2)
  console.log('C');          // 재개되면 μ—¬κΈ°λΆ€ν„°
  return 3;                  // μ’…λ£Œ (κ°’ 3)
}

const it = steps();

console.log(it.next()); // { value: 1, done: false }  β–Ά 'A'κΉŒμ§€ μ‹€ν–‰ ν›„ 첫 yieldμ—μ„œ 멈좀
console.log(it.next()); // { value: 2, done: false }  β–Ά 'B' μ‹€ν–‰ ν›„ 두 번째 yieldμ—μ„œ 멈좀
console.log(it.next()); // { value: 3, done: true }   β–Ά 'C' μ‹€ν–‰ ν›„ return으둜 끝

 

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

일반 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ λ§€κ°œλ³€μˆ˜λ₯Ό 톡해 ν•¨μˆ˜ μ™ΈλΆ€μ—μ„œ 값을 μ£Όμž…λ°›κ³  ν•¨μˆ˜ μ½”λ“œλ₯Ό 일괄 μ‹€ν–‰ν•˜μ—¬ 결과값을 ν•¨μˆ˜ μ™ΈλΆ€λ‘œ λ°˜ν™˜.

즉, ν•¨μˆ˜κ°€ μ‹€ν–‰λ˜κ³  μžˆλŠ” λ™μ•ˆμ—λŠ” ν•¨μˆ˜ μ™ΈλΆ€μ—μ„œ ν•¨μˆ˜ λ‚΄λΆ€λ‘œ 값을 μ „λ‹¬ν•˜μ—¬ ν•¨μˆ˜μ˜ μƒνƒœλ₯Ό λ³€κ²½ X

μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” ν•¨μˆ˜ ν˜ΈμΆœμžμ—κ²Œ μƒνƒœλ₯Ό 전달할 수 있고, ν•¨μˆ˜ ν˜ΈμΆœμžλ‘œλΆ€ν„° μƒνƒœλ₯Ό 전달받을 수 μžˆλ‹€.

 

 

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

일반 ν•¨μˆ˜λŠ” ν•¨μˆ˜μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜κ³  값을 λ°˜ν™˜

μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜ : ν•¨μˆ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜λŠ” 것이 μ•„λ‹ˆλΌ μ΄ν„°λŸ¬λΈ”μ΄λ©΄μ„œ λ™μ‹œμ— μ΄ν„°λ ˆμ΄ν„°μΈ μ œλ„ˆλ ˆμ΄ν„° 객체λ₯Ό λ°˜ν™˜.

function* askName() {
  const name = yield '이름이 λ­μ—μš”?';   // a
  return `μ•ˆλ…•ν•˜μ„Έμš”, ${name}λ‹˜!`;       // b
}

const it2 = askName();                    // A
console.log(it2.next());                  // B
console.log(it2.next('μ€μ„œ'));            // C

 

A. askName을 function* 으둜 μ •μ˜λ˜μ—ˆμœΌλ―€λ‘œ μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜, μ§€κΈˆμ€ μ½”λ“œκ°€ μ‹€ν–‰λ˜μ§€ μ•ŠμŒ

λŒ€μ‹  μ œλ„ˆλ ˆμ΄ν„° 객체 it2λ₯Ό λ°˜ν™˜

→ it2λŠ” next/return/throw λ©”μ„œλ“œλ₯Ό κ°€μ§„ μ΄ν„°λ ˆμ΄ν„°

B. it2. next() 호좜

  • μ œλ„ˆλ ˆμ΄ν„° 싀행이 μ‹œμž‘λ˜μ–΄ yield 쀄
  • a μ€„μ—μ„œ yield '이름이 λ­μ—μš”?'λ₯Ό λ§Œλ‚˜λ©΄:
    • λ°–μœΌλ‘œ λ‚΄λ³΄λ‚΄λŠ” κ°’(value): '이름이 λ­μ—μš”?'
    • μΌμ‹œ 쀑지 μœ„μΉ˜: a μ€„μ˜ yield ν‘œν˜„μ‹ λ°”λ‘œ λ’€ (λŒ€μž…μ‹μ˜ 였λ₯Έμͺ½)
    • next()의 λ°˜ν™˜: { value: '이름이 λ­μ—μš”?', done: false }
  • μ€‘μš”: 이 μˆœκ°„ a의 const name = …λŠ” 아직 μ™„λ£Œλ˜μ§€ μ•Šμ•˜μŒ.
  • yieldλŠ” “값을 밖에 내보내고 멈좘” μƒνƒœμΌ 뿐

C. it2.next(’μ€μ„œ’)

  • 멈좰 있던 지점(β‘ μ˜ yield)μ—μ„œ λ‹€μ‹œ μž¬κ°œλœλ‹€.
  • 이번 next('μ€μ„œ')둜 μ „λ‹¬ν•œ 값은, λ°”λ‘œ 직전 yield ν‘œν˜„μ‹μ˜ κ²°κ³Όκ°€ λœλ‹€.
    • 즉, const name = (yield '이름이 λ­μ—μš”?')μ—μ„œ
    • nameμ—λŠ” 'μ€μ„œ'κ°€ λŒ€μž…λœλ‹€.
  • μ΄μ–΄μ„œ b 쀄 μ‹€ν–‰: return μ•ˆλ…•ν•˜μ„Έμš”, ${name}λ‹˜!``
  • → μ΅œμ’… λ°˜ν™˜κ°’ 'μ•ˆλ…•ν•˜μ„Έμš”, μ€μ„œλ‹˜!'을 내보내며 μ’…λ£Œ.
  • next('μ€μ„œ')의 λ°˜ν™˜: { value: 'μ•ˆλ…•ν•˜μ„Έμš”, μ€μ„œλ‹˜!', done: true }

 


 

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

  • function* ν‚€μ›Œλ“œλ‘œ μ„ μ–Έ
  • ν•˜λ‚˜ μ΄μƒμ˜ yield ν‘œν˜„μ‹μ„ 포함
  • λ‚˜λ¨Έμ§€λŠ” 일반 ν•¨μˆ˜ μ •μ˜μ™€ 동일
// μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜ μ„ μ–Έλ¬Έ
function* genDecFunc() {
  yield 1;
}

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

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

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

 

← *(μ• μŠ€ν„°λ¦¬μŠ€ν¬) 의 μœ„μΉ˜λŠ” functonκ³Ό ν•¨μˆ˜λͺ… 사이면 λ‹€ κ°€λŠ₯

일관성을 μœ„ν•΄ function* ꢌμž₯

function* genFunc() { yield 1; } //ꢌμž₯

function * genFunc() { yield 1; }

function *genFunc() { yield 1; }

function*genFunc() { yield 1; }

μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” ν™”μ‚΄ν‘œ ν•¨μˆ˜λ‘œ μ •μ˜ X

const genArrowFunc = * () => {
  yield 1; //μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜κ°€ μ•„λ‹ˆλ―€λ‘œ yield μ‚¬μš© λΆˆκ°€
}; // SyntaxError: Unexpected token '*'
  • μ œλ„ˆλ ˆμ΄ν„° ν‘œκΈ°λŠ” function* λ˜λŠ” **async function**μ—λ§Œ λΆ™λŠ” μ „μš© 문법
  • ν™”μ‚΄ν‘œ ν•¨μˆ˜ 문법( () => {} )μ—λŠ” λ₯Ό 뢙일 μžλ¦¬κ°€ μ•„μ˜ˆ μ—†μŒ
  • 즉, ν™”μ‚΄ν‘œ ν•¨μˆ˜μ˜ 문법 κ·œμΉ™μ— * 토큰(μ œλ„ˆλ ˆμ΄ν„° ν‘œμ§€)이 ν¬ν•¨λ˜μ–΄ μžˆμ§€ μ•ŠκΈ° λ•Œλ¬Έμ— νŒŒμ„œκ°€ *λ₯Ό 보고 SyntaxErrorλ₯Ό λ‚Έλ‹€

μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” new μ—°μ‚°μžμ™€ ν•¨κ»˜ μƒμ„±μž ν•¨μˆ˜λ‘œ 호좜X

function* genFunc() {
  yield 1;
}

new genFunc(); // TypeError: genFunc is not a constructor
  • newκ°€ λ™μž‘ν•˜λ €λ©΄ ν•¨μˆ˜κ°€ μƒμ„±μž(constructible) μ—¬μ•Ό ν•œλ‹€
  • 즉, λ‚΄λΆ€μ μœΌλ‘œ [[Construct]]λΌλŠ” λ™μž‘μ„ κ°€μ Έμ•Ό ν•œλ‹€
  • μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” “μƒμ„±μž”κ°€ μ•„λ‹™λ‹ˆλ‹€. ν˜ΈμΆœν•˜λ©΄ 객체λ₯Ό μƒμ„±ν•˜λŠ” λŒ€μ‹  “μ œλ„ˆλ ˆμ΄ν„°(μ΄ν„°λ ˆμ΄ν„°) 객체”λ₯Ό λ°˜ν™˜ν•˜λŠ” νŒ©ν† λ¦¬ μ—­ν• λ§Œ 함
  • → new genFunc()λ₯Ό ν•˜λ©΄ TypeError: not a constructor

 


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

  • μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ 일반 ν•¨μˆ˜μ²˜λŸΌ ν•¨μˆ˜ μ½”λ“œ 블둝을 μ‹€ν–‰ν•˜λŠ” 것이 μ•„λ‹ˆλΌ μ œλ„ˆλ ˆμ΄ν„° 객체λ₯Ό 생성해 λ°˜ν™˜
  • μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜κ°€ λ°˜ν™˜ν•œ μ œλ„ˆλ ˆμ΄ν„° κ°μ²΄λŠ” μ΄ν„°λŸ¬λΈ”μ΄λ©΄μ„œ λ™μ‹œμ— μ΄ν„°λ ˆμ΄ν„°

→ Symbol.iterator λ©”μ„œλ“œλ₯Ό μƒμ†λ°›λŠ” μ΄ν„°λŸ¬λΈ”

→ value, done ν”„λ‘œνΌν‹°λ₯Ό κ°€μ§€λŠ” μ΄ν„°λ ˆμ΄ν„° result 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” next λ©”μ„œλ“œ μ†Œμœ ν•˜λŠ” μ΄ν„°λ ˆμ΄ν„°

function* steps() {
  console.log('A');          // μ‹œμž‘
  yield 1;                   // ⟡ μ—¬κΈ°μ„œ μΌμ‹œμ€‘μ§€ (κ°’ 1을 λ°–μœΌλ‘œ 보냄)
  console.log('B');          // 재개되면 μ—¬κΈ°λΆ€ν„°
  yield 2;                   // ⟡ 또 쀑지 (κ°’ 2)
  console.log('C');          // 재개되면 μ—¬κΈ°λΆ€ν„°
  return 3;                  // μ’…λ£Œ (κ°’ 3)
}

const it = steps();

console.log(it.next()); // { value: 1, done: false }  β–Ά 'A'κΉŒμ§€ μ‹€ν–‰ ν›„ 첫 yieldμ—μ„œ 멈좀
console.log(it.next()); // { value: 2, done: false }  β–Ά 'B' μ‹€ν–‰ ν›„ 두 번째 yieldμ—μ„œ 멈좀
console.log(it.next()); // { value: 3, done: true }   β–Ά 'C' μ‹€ν–‰ ν›„ return으둜 끝

→ next λ©”μ„œλ“œ : value, done ν”„λ‘œνΌν‹°λ₯Ό κ°€μ§€λŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜

// μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜
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

next return throw

value yield 된 κ°’ 인자둜 전달 받은 κ°’ undefined
done 뒀에 λ‚¨μ•„μžˆμœΌλ©΄ false, return으둜 뒀에 μ—†μœΌλ©΄ true true true

μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜μ˜ yield ν‘œν˜„μ‹κΉŒμ§€ μ½”λ“œ λΈ”λŸ­μ„ μ‹€ν–‰ν•˜κ³ 

  • value : yield 된 κ°’
  • done : 뒀에 λ‚¨μœΌλ©΄ false, return을 λ§Œλ‚˜κ³  λλ‚˜λ©΄ true

μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜

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}

 

return

  • value : 인수둜 전달받은 κ°’
  • done : true

μ΄λŸ¬ν…Œμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜

throw

  • 인수둜 전달받은 μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€κ³ 
  • value : undefined
  • done : true

μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜

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.throw('Error!')); // {value: undefined, done: true}

 


 

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

yield ν‚€μ›Œλ“œ → μ‹€ν–‰ 쀑지 or yield ν‚€μ›Œλ“œ 뒀에 μ˜€λŠ” ν‘œν˜„μ‹μ˜ 평과 κ²°κ³Όλ₯Ό μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜ ν˜ΈμΆœμžμ—κ²Œ λ°˜ν™˜

next λ©”μ„œλ“œ → ν•„μš”ν•œ μ‹œμ μ— λ‹€μ‹œ 재개

// μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜
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}

 

 

μ œλ„ˆλ ˆμ΄ν„° 객체의 next λ©”μ„œλ“œμ— μ „λ‹¬ν•œ μΈμˆ˜λŠ” μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜μ˜ yield ν‘œν˜„μ‹μ„ ν• λ‹Ήλ°›λŠ” λ³€μˆ˜μ— ν• λ‹Ή.
yield ν‘œν˜„μ‹μ„ ν• λ‹Ήλ°›λŠ” λ³€μˆ˜μ— yield ν‘œν˜„μ‹μ˜ 평가 κ²°κ³Όκ°€ ν• λ‹Ήλ˜μ§€ μ•ŠλŠ” 것에 주의

 

function* genFunc() {
  // 첫 next()λ₯Ό ν˜ΈμΆœν•˜λ©΄ 첫 번째 yieldκΉŒμ§€ μ‹€ν–‰λ˜κ³  μΌμ‹œ μ€‘μ§€λœλ‹€.
  // μ΄λ•Œ next()의 λ°˜ν™˜ κ°μ²΄λŠ” { value: 1, done: false }이며,
  // 아직 xμ—λŠ” 아무 값도 λ“€μ–΄κ°€μ§€ μ•Šμ•˜λ‹€(λ‹€μŒ next(arg)둜 결정됨).
  const x = yield 1;

  // 두 번째 next(100)을 ν˜ΈμΆœν•˜λ©΄, μ „λ‹¬ν•œ 100이 λ°”λ‘œ 직전 yield ν‘œν˜„μ‹μ˜ 값이 λ˜μ–΄ x에 λŒ€μž…λœλ‹€.
  // μ΄μ–΄μ„œ μ‹€ν–‰λ˜μ–΄ 두 번째 yieldμ—μ„œ (x + 10) = 110을 λ°–μœΌλ‘œ 내보내고 μΌμ‹œ μ€‘μ§€ν•œλ‹€.
  // λ§ˆμ°¬κ°€μ§€λ‘œ 아직 yμ—λŠ” 아무 값도 λ“€μ–΄μ§€ μ•Šμ•˜λ‹€.
  const y = yield (x + 10);

  // μ„Έ 번째 next(50)을 ν˜ΈμΆœν•˜λ©΄, μ „λ‹¬ν•œ 50이 직전 yield ν‘œν˜„μ‹μ˜ 값이 λ˜μ–΄ y에 λŒ€μž…λœλ‹€.
  // μ΄μ–΄μ„œ ν•¨μˆ˜ λκΉŒμ§€ μ‹€ν–‰λ˜λ©°, λ°˜ν™˜κ°’ x + y = 100 + 50 = 150을 내보내고 done: true둜 μ’…λ£Œν•œλ‹€.
  return x + y;
}

// μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ '싀행을 미룬' μ œλ„ˆλ ˆμ΄ν„° 객체(μ΄ν„°λ ˆμ΄ν„°)λ₯Ό λ°˜ν™˜ν•œλ‹€.
const generator = genFunc(0); // 인자 0은 λ¬΄μ‹œλ¨(첫 next μ „κΉŒμ§€λŠ” μ–΄λ–€ μΈμžλ„ μ „λ‹¬λ˜μ§€ μ•ŠμŒ).

// 1) 첫 호좜: 인자λ₯Ό 주더라도 λ¬΄μ‹œλœλ‹€. 첫 번째 yield(1)κΉŒμ§€ μ‹€ν–‰ν•˜κ³  λ©ˆμΆ˜λ‹€.
let res = generator.next();
console.log(res); // { value: 1, done: false }

// 2) 두 번째 호좜: next(100)
//    이전 yield의 κ²°κ³Όκ°€ λ˜μ–΄ x = 100이 λœλ‹€.
//    μ΄μ–΄μ„œ 두 번째 yieldμ—μ„œ (x + 10) = 110을 내보내고 λ©ˆμΆ˜λ‹€.
res = generator.next(100);
console.log(res); // { value: 110, done: false }

// 3) μ„Έ 번째 호좜: next(50)
//    이전 yield의 κ²°κ³Όκ°€ λ˜μ–΄ y = 50이 λœλ‹€.
//    ν•¨μˆ˜κ°€ λκΉŒμ§€ μ‹€ν–‰λ˜λ©° x (100) + y (50) = 150을 λ°˜ν™˜ν•˜κ³  μ’…λ£Œν•œλ‹€.
res = generator.next(50);
console.log(res); // { value: 150, done: true }

  • next()둜 μ „λ‹¬ν•œ μΈμžλŠ” 이전 yield ν‘œν˜„μ‹μ„ ν• λ‹Ή λ°›λŠ” λ³€μˆ˜μ— 듀어감
  • → 맨 처음으둜 μ „λ‹¬ν•œ μΈμžλŠ” λ¬΄μ‹œλœλ‹€.

 

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

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

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

→ μ™œ? μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜κ°€ μ΄ν„°λŸ¬λΈ”ν•˜λ©΄μ„œ λ™μ‹œμ— μ΄ν„°λ ˆμ΄ν„°μ΄λ―€λ‘œ

// λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”μ„ μƒμ„±ν•˜λŠ” ν•¨μˆ˜
const infiniteFibonacci = (function () {
  let [pre, cur] = [0, 1];        // ⬅️ νμ‡„λœ μƒνƒœ(ν΄λ‘œμ €): 이전값/ν˜„μž¬κ°’ μ €μž₯

  return {
    [Symbol.iterator]() { return this; }, // ⬅️ μ΄ν„°λŸ¬λΈ”: for..ofκ°€ λΆ€λ₯Ό λ•Œ
    next() {                              // ⬅️ μ΄ν„°λ ˆμ΄ν„°: ν•œ 걸음 μ§„ν–‰
      [pre, cur] = [cur, pre + cur];      // ν”Όλ³΄λ‚˜μΉ˜ μ „μ§„
      return { value: cur };              // done μƒλž΅ => λ¬΄ν•œ
    }
  };
}());

// infiniteFibonacciλŠ” λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”μ΄λ‹€.
for (const num of infiniteFibonacci) {
  if (num > 10000) break;
  console.log(num); // 1 2 3 5 8...2584 4181 6765
}
  • IIFE(μ¦‰μ‹œ μ‹€ν–‰ ν•¨μˆ˜) κ°€ ν•œ 번 μ‹€ν–‰λ˜μ–΄ 객체λ₯Ό λ°˜ν™˜ν•˜κ³ , κ·Έ λ°˜ν™˜λœ 객체λ₯Ό infiniteFibonacci에 λ‹΄μŒ.
  • λ°˜ν™˜λœ κ°μ²΄λŠ”:
    • Symbol.iterator λ©”μ„œλ“œκ°€ μžˆμ–΄μ„œ μ΄ν„°λŸ¬λΈ”μ΄κ³ ,
    • next() λ©”μ„œλ“œκ°€ μžˆμ–΄μ„œ μ΄ν„°λ ˆμ΄ν„°μ΄κΈ°λ„ 함.
    • return this 덕뢄에 “μ΄ν„°λŸ¬λΈ” === μ΄ν„°λ ˆμ΄ν„°” ν˜•νƒœ(= 자기 μžμ‹ μ΄ 반볡자).

즉, for (const x of infiniteFibonacci)κ°€ μ‹œμž‘λ˜λ©΄,

  • 엔진은 infiniteFibonacci[Symbol.iterator]()λ₯Ό 호좜 → 자기 μžμ‹ μ„ λ°›μŒ
  • 그리고 λ§€ λ°˜λ³΅λ§ˆλ‹€ next()λ₯Ό ν˜ΈμΆœν•΄ { value, done }λ₯Ό λ°›μŒ
[pre, cur] = [cur, pre + cur];
return { value: cur };

 

호좜 κ°±μ‹  ν›„ (pre, cur) λ°˜ν™˜ value

1번째 next (1, 1) 1
2번째 next (1, 2) 2
3번째 next (2, 3) 3
4번째 next (3, 5) 5
5번째 next (5, 8) 8
… … …

μœ„μ— μ½”λ“œλ³΄λ‹€ μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ 더 κ°„λ‹¨ν•˜λ‹€.

// λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”μ„ μƒμ„±ν•˜λŠ” μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜
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
}
  • yield cur κ°€ μžˆλŠ” λΆ€λΆ„κΉŒμ§€ ν˜ΈμΆœν•œ ν›„ λ‹€μŒ nextμ—μ„œλŠ” while true둜 λ˜μ–΄ μžˆμœΌλ―€λ‘œ λ‹€μ‹œ while 문을 반볡

 

2. 비동기 처리

 

next λ©”μ„œλ“œμ™€ yield ν‘œν˜„μ‹μ„ 톡해 ν•¨μˆ˜ ν˜ΈμΆœμžμ™€ ν•¨μˆ˜μ˜ μƒνƒœλ₯Ό μ£Όκ³  받을 수 μžˆλ‹€

→ ν”„λ‘œλ―ΈμŠ€λ₯Ό μ‚¬μš©ν•œ 비동기 처리λ₯Ό 동기 처리처럼 κ΅¬ν˜„

→ ν”„λ‘œλ―ΈμŠ€μ˜ 후속 처리 λ©”μ„œλ“œ then/catch/finally 없이 비동기 처리 κ²°κ³Ό λ°˜ν™˜ν•˜λ„λ‘ κ΅¬ν˜„ κ°€λŠ₯

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

// 🧩 μ œλ„ˆλ ˆμ΄ν„° μ‹€ν–‰κΈ°
const async = generatorFunc => {
  const generator = generatorFunc(); // 1️⃣ μ œλ„ˆλ ˆμ΄ν„° 객체 생성

  const onResolved = arg => {
    const result = generator.next(arg); // 2️⃣ next() μ‹€ν–‰

    return result.done
      ? result.value // 7️⃣ μ œλ„ˆλ ˆμ΄ν„° μ™„λ£Œ μ‹œ value λ°˜ν™˜
      : result.value.then(res => onResolved(res)); // 3️⃣ ν”„λ‘œλ―ΈμŠ€ resolve ν›„ μž¬κ·€ 호좜
  };

  return onResolved; // 4️⃣ ν΄λ‘œμ €(onResolved) λ°˜ν™˜
};

// πŸŒ€ μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜ μ‹€ν–‰
(async(function* fetchTodo() { // 5️⃣ async ν•¨μˆ˜ 호좜
  const url = '<https://jsonplaceholder.typicode.com/todos/1>';

  const response = yield fetch(url); // 6️⃣ fetch() → ν”„λ‘œλ―ΈμŠ€ λ°˜ν™˜
  const todo = yield response.json(); // 8️⃣ response.json() → ν”„λ‘œλ―ΈμŠ€ λ°˜ν™˜
  console.log(todo); // {userId: 1, id: 1, title: 'delectus aut autem', completed: false}
})()); // 9️⃣ λ°˜ν™˜λœ onResolved() μ¦‰μ‹œ μ‹€ν–‰

1️⃣ μ œλ„ˆλ ˆμ΄ν„° 객체 생성

  • async(generatorFunc)κ°€ 호좜되면 λ‚΄λΆ€μ—μ„œ generatorFunc()—즉 fetchTodo() μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜κ°€ μ‹€ν–‰λ§Œ ν•΄μ„œ(μ‹œμž‘ X) μ œλ„ˆλ ˆμ΄ν„° 객체(generator)λ₯Ό λ§Œλ“ λ‹€.
  • 아직 fetchTodo 본문은 첫 쀄도 μ§„ν–‰λ˜μ§€ μ•Šμ•˜μŒ. μ œλ„ˆλ ˆμ΄ν„°λŠ” next()κ°€ λ“€μ–΄μ˜€λ©΄ κ·Έλ•ŒλΆ€ν„° λˆλ‹€.
  • onResolved λŠ” generator λ₯Ό 캑쳐(κΈ°μ–΅)ν•˜κ³  μžˆμœΌλ―€λ‘œ, μ–Έμ œλ“ μ§€ 호좜되면 generator.next() μ‹€ν–‰ κ°€λŠ₯ → 클둜져

2️⃣ 첫 번째 next() 호좜

  • onResolved()κ°€ 처음 ν˜ΈμΆœλœλ‹€(인수 μ—†μŒ → undefined).
  • λ‚΄λΆ€μ—μ„œ generator.next(undefined) μ‹€ν–‰ → fetchTodoκ°€ 처음으둜 달리기 μ‹œμž‘.
  • const response = yield fetch(url); κΉŒμ§€ μ§„ν–‰λ˜κ³  멈좀.
    • μ΄λ•Œ result = { value: Promise<Response>, done: false }.
    • 즉, **멈좘 μœ„μΉ˜λŠ” yield fetch(url)*이고, valueλŠ” fetch(url)이 λ°˜ν™˜ν•œ ν”„λ‘œλ―ΈμŠ€.

3️⃣ ν”„λ‘œλ―ΈμŠ€κ°€ ν•΄κ²°λ˜λ©΄ μž¬κ·€ 재개

  • done:falseμ΄λ―€λ‘œ result.value.then(res => onResolved(res))둜 등둝.
  • fetch(url)이 resolve되면, κ·Έ κ²°κ³Ό(Response 객체)λ₯Ό λ“€κ³  λ‹€μ‹œ onResolved(res) 호좜(μž¬κ·€ μ§„μž…).
  • μš” ν¬μΈνŠΈκ°€ 핡심: yieldμ—μ„œ “멈좘” μ œλ„ˆλ ˆμ΄ν„°λ₯Ό, ν”„λ‘œλ―ΈμŠ€κ°€ λλ‚œ κ°’μœΌλ‘œ λ‹€μ‹œ κΉ¨μ›Œμ€€λ‹€λŠ” 것.

4️⃣ ν΄λ‘œμ €(onResolved) λ°˜ν™˜

  • 1️⃣ λ‹¨κ³„μ—μ„œ μ–ΈκΈ‰ν•œ λŒ€λ‘œ, async()λŠ” onResolvedλ₯Ό λ¦¬ν„΄ν•˜κ³  λλ‚œλ‹€.
  • μ½”λ“œμ—μ„œλŠ” 이 λ°˜ν™˜κ°’μ„ μ¦‰μ‹œ μ‹€ν–‰(IIFE) ν•˜λ„λ‘ 적어놨기 λ•Œλ¬Έμ—(→ 9️⃣) 흐름이 이어진닀.
  • κΈ°μ–΅ν•˜μž: onResolvedλŠ” generatorλ₯Ό μΊ‘μ²˜ν•΄μ„œ, μ–Έμ œλ“ μ§€ μ™ΈλΆ€μ—μ„œ λ‹€μ‹œ next()λ₯Ό 눌러 이어 달릴 수 있게 λ§Œλ“  λ²„νŠΌ 같은 쑴재.

5️⃣ λ°˜ν™˜λœ onResolved μ¦‰μ‹œ μ‹€ν–‰(IIFE)

  • μ†ŒμŠ€μ˜ (... )(); 뢀뢄이 λ°”λ‘œ 이거.
  • async(fetchTodo) → onResolved λ°˜ν™˜ → κ³§λ°”λ‘œ onResolved() 호좜.
  • μ—¬κΈ°μ„œ 2️⃣이 μ‹œμž‘λœλ‹€κ³  봐도 λœλ‹€(처음 next()κ°€ νŠΈλ¦¬κ±°λ˜λŠ” 지점).

6️⃣ 두 번째 next(res) — Response μ£Όμž…

  • 3οΈβƒ£μ—μ„œ λ“±λ‘ν–ˆλ˜ .then이 뢈리면, onResolved(res)κ°€ ν˜ΈμΆœλœλ‹€.
  • λ‚΄λΆ€μ—μ„œ generator.next(res) μ‹€ν–‰ → 방금 받은 Responseκ°€ fetchTodo의 response λ³€μˆ˜μ— ν• λ‹Ήλ˜λ©΄μ„œ λ‹€μŒ μ€„λ‘œ μ§„ν–‰.
  • 이제 const todo = yield response.json(); κΉŒμ§€ κ°€μ„œ λ‹€μ‹œ 멈좀.
    • 이번 result = { value: Promise<Todo>, done: false }.

8️⃣ μ„Έ 번째 next(todo) — 데이터 μ£Όμž…

  • response.json()이 resolve되면 또 onResolved(todo) 호좜.
  • generator.next(todo) μ‹€ν–‰ → todoκ°€ λ³€μˆ˜μ— ν• λ‹Ήλ˜κ³ , console.log(todo)κΉŒμ§€ 끝.
  • μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜ 본문이 λλ‚¬μœΌλ―€λ‘œ λ‹€μŒ next() κ²°κ³ΌλŠ”
  • result = { value: undefined, done: true }.

9️⃣ μ™„λ£Œ 처리 (done:true)

  • done:trueμ΄λ―€λ‘œ onResolvedλŠ” result.value—즉 undefined—λ₯Ό κ·ΈλŒ€λ‘œ λ¦¬ν„΄ν•˜κ³  μž¬κ·€ μ’…λ£Œ.
  • μž¬κ·€λ‘œ μŒ“μ˜€λ˜ onResolved(...) ν˜ΈμΆœλ“€μ΄ 순차적으둜 μ–Έμ™€μΈλ“œλ˜λ©° λͺ¨λ‘ undefined둜 λλ‚œλ‹€.

7️⃣ μ΅œμ’… λ°˜ν™˜κ°’μ€ undefined

  • μ œλ„ˆλ ˆμ΄ν„°μ˜ λ°˜ν™˜κ°’(μ—¬κΈ°μ„œλŠ” λͺ…μ‹œμ  return μ—†μœΌλ‹ˆ undefined)이 μ΅œμ’… κ°’.
  • 즉, 이 “μ‹€ν–‰κΈ°”λŠ” 비동기 λ™μž‘μ„ 순차둜 ν’€μ–΄μ£ΌλŠ” μ—­ν• λ§Œ ν•˜κ³ , νŠΉλ³„ν•œ 값을 λŒλ €μ£Όμ§„ μ•ŠλŠ”λ‹€.

 

 

μœ„ μ½”λ“œλ₯Ό async/await을 μ‚¬μš©ν•˜λ©΄ μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜μ™€ 같이 μ‹€ν–‰ν•  ν•„μš” μ—†λ‹€

const fetch = require('node-fetch'); // 1️⃣ node ν™˜κ²½μ—μ„œ fetch μ‚¬μš©μ„ μœ„ν•œ λͺ¨λ“ˆ
const co = require('co'); // 2️⃣ co: μ œλ„ˆλ ˆμ΄ν„° 기반 비동기 μ‹€ν–‰κΈ°

co(function* fetchTodo() { // 3️⃣ co()κ°€ μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό μ‹€ν–‰
  const url = '<https://jsonplaceholder.typicode.com/todos/1>';

  const response = yield fetch(url); // 4️⃣ fetch() → Promise λ°˜ν™˜ → coκ°€ resolve될 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦Ό
  const todo = yield response.json(); // 5️⃣ response.json() → Promise λ°˜ν™˜ → coκ°€ resolve될 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦Ό
  console.log(todo); // 6️⃣ μ΅œμ’… 데이터 좜λ ₯
});

 

3️⃣ co(function* fetchTodo() { ... })κ°€ 호좜

co()λŠ” 이 μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•˜λ©΄μ„œ λ‚΄λΆ€μ—μ„œ next()λ₯Ό 계속 λˆŒλŸ¬μ£ΌλŠ” μ—­ν• 

→ coκ°€ λŒ€μ‹  “ν”„λ‘œλ―ΈμŠ€κ°€ 끝날 λ•Œλ§ˆλ‹€ μ•Œμ•„μ„œ λ‹€μŒ next() 호좜 → 비동기 흐름을 μžλ™μœΌλ‘œ μˆœμ„œλŒ€λ‘œ μ΄μ–΄μ£ΌλŠ” κ΄€λ¦¬μž

4️⃣ μ œλ„ˆλ ˆμ΄ν„° λ‚΄λΆ€μ—μ„œ const response = yield fetch(url);이 μ‹€ν–‰

  • fetch(url)은 λ„€νŠΈμ›Œν¬ μš”μ²­μ„ 보내고 Promise<Response>λ₯Ό λ°˜ν™˜
  • yieldλ₯Ό λ§Œλ‚˜λ©΄ ν•¨μˆ˜ 멈좀
  • co λŠ” fetch(url)이 μ™„λ£Œλ  λ•ŒκΉŒμ§€ κΈ°λ‹€λ Έλ‹€κ°€ κ²°κ³Ό Response 객체λ₯Ό λ‹€μ‹œ next()인수둜 λ„£μ–΄μ„œ μ œλ„ˆλ ˆμ΄ν„° 재개

5️⃣ const todo = yield response.json();

  • response.json() μ—­μ‹œ 비동기 ν•¨μˆ˜μ΄λ―€λ‘œ Promiseλ₯Ό λ°˜ν™˜
  • 또 ν•œ 번 yieldμ—μ„œ λ©ˆμΆ”κ³ , coκ°€ κΈ°λ‹€λ¦½λ‹ˆλ‹€.
  • κ·Έ Promiseκ°€ resolve되면, 즉 JSON λ³€ν™˜μ΄ λλ‚˜λ©΄
    • κ·Έ κ²°κ³Ό 객체(todo 데이터)κ°€ next() 의 인수둜 μ „λ‹¬λ˜μ–΄ todo λ³€μˆ˜μ— μ €μž₯

6️⃣ console.log(todo)

{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}


6. async/await

μ œλ„ˆλ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•΄μ„œ 비동기 처리λ₯Ό 동기 처리처럼 λ™μž‘ν•˜λ„λ‘ κ΅¬ν˜„ν•˜λ©΄ μ½”λ“œκ°€ κΈΈμ–΄μ Έμ„œ 가독성 μ €ν•˜

→ ES8λΆ€ν„° async/await λ„μž…

  • ν”„λ‘œλ―ΈμŠ€ 기반 λ™μž‘
  • then/catch/fianlly 후속 처리 λ©”μ„œλ“œμ— 콜백 ν•¨μˆ˜λ₯Ό μ „λ‹¬ν•΄μ„œ 비동기 처리 κ²°κ³Όλ₯Ό 후속 μ²˜λ¦¬ν•  ν•„μš” 없이 마치 동기 처리처럼 ν”„λ‘œλ―ΈμŠ€ μ‚¬μš© κ°€λŠ₯
const fetch = require('node-fetch'); // 1️⃣ node ν™˜κ²½μ—μ„œ fetch μ‚¬μš©μ„ μœ„ν•œ λͺ¨λ“ˆ
const co = require('co'); // 2️⃣ co: μ œλ„ˆλ ˆμ΄ν„° 기반 비동기 μ‹€ν–‰κΈ°

co(function* fetchTodo() { // 3️⃣ co()κ°€ μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό μ‹€ν–‰
  const url = '<https://jsonplaceholder.typicode.com/todos/1>';

  const response = yield fetch(url); // 4️⃣ fetch() → Promise λ°˜ν™˜ → coκ°€ resolve될 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦Ό
  const todo = yield response.json(); // 5️⃣ response.json() → Promise λ°˜ν™˜ → coκ°€ resolve될 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦Ό
  console.log(todo); // 6️⃣ μ΅œμ’… 데이터 좜λ ₯
});

μ΄κ±°λŠ” μœ„μ—μ„œ 봀던 μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜ 없이 async ν•¨μˆ˜λ‘œ κ΅¬ν˜„

1. async ν•¨μˆ˜

  1. await ν‚€μ›Œλ“œλŠ” λ°˜λ“œμ‹œ async ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.
  2. async ν•¨μˆ˜λŠ” async ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄ μ •μ˜ν•˜λ©° μ–Έμ œλ‚˜ ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•œλ‹€.
  3. async ν•¨μˆ˜κ°€ λͺ…μ‹œμ μœΌλ‘œ ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•˜μ§€ μ•Šλ”λΌλ„ async ν•¨μˆ˜λŠ” μ•”λ¬΅μ μœΌλ‘œ λ°˜ν™˜κ°’μ„ resolve ν•˜λŠ” ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•œλ‹€.
async function foo() {
  return 1;
}
// μ•„λž˜ 두 μ½”λ“œλŠ” κ°™λ‹€
foo().then(console.log); // 1
Promise.resolve(1).then(console.log); // 1

→ async ν‚€μ›Œλ“œλŠ” 항상 Promise 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜λ₯Ό λ§Œλ“ λ‹€

즉, ν•¨μˆ˜ μ•ˆμ—μ„œ return 1;처럼 ν‰λ²”ν•˜κ²Œ λ°˜ν™˜ν•΄λ„, μ‹€μ œ λ°˜ν™˜κ°’μ€ Promise.resolve(1) 이 λœλ‹€

1. async ν•¨μˆ˜ μ„ μ–Έλ¬Έ

async function foo(n) { return n; }
foo(1).then(v => console.log(v)); // 1
  • 일반 ν•¨μˆ˜ μ„ μ–Έ(function foo) μ•žμ— async ν‚€μ›Œλ“œλ₯Ό 뢙인 ν˜•νƒœ.
  • 호좜 μ‹œ Promise둜 감싸진 값을 λ°˜ν™˜ → .then()으둜 κ²°κ³Ό 처리 κ°€λŠ₯.

2. async ν•¨μˆ˜ ν‘œν˜„μ‹

const bar = async function (n) { return n; };
bar(2).then(v => console.log(v)); // 2
  • 이름 μ—†λŠ” ν•¨μˆ˜μ— asyncλ₯Ό λΆ™μ—¬ λ³€μˆ˜μ— ν• λ‹Ή.
  • 첫 번째 μ˜ˆμ‹œμ™€ λ™μž‘μ€ κ°™κ³ , 읡λͺ… ν•¨μˆ˜ ν˜•νƒœλ‘œ μ‚¬μš©ν•  수 있음.

3. async ν™”μ‚΄ν‘œ ν•¨μˆ˜

const baz = async n => n;
baz(3).then(v => console.log(v)); // 3
  • ν™”μ‚΄ν‘œ ν•¨μˆ˜ 버전.
  • ν•œ 쀄일 경우 {}와 return을 μƒλž΅ κ°€λŠ₯.
  • async + ν™”μ‚΄ν‘œ ν•¨μˆ˜ 쑰합은 짧은 비동기 콜백 μž‘μ„±μ— 자주 μ‚¬μš©λ¨.
  • 예: arr.map(async item => await fetch(item))

4. async λ©”μ„œλ“œ (객체 λ¦¬ν„°λŸ΄ μ•ˆ)

const obj = {
  async foo(n) { return n; }
};
obj.foo(4).then(v => console.log(v)); // 4
  • 객체 λ©”μ„œλ“œμ— asyncλ₯Ό 뢙인 ν˜•νƒœ.
  • 객체의 ν”„λ‘œνΌν‹° fooκ°€ 비동기 ν•¨μˆ˜κ°€ λ˜μ–΄ Promise λ°˜ν™˜.

5. async 클래슀 λ©”μ„œλ“œ

class MyClass {
  async bar(n) { return n; }
}
const myClass = new MyClass();
myClass.bar(5).then(v => console.log(v)); // 5
  • 클래슀 λ‚΄λΆ€ λ©”μ„œλ“œμ— asyncλ₯Ό 뢙이면, κ·Έ λ©”μ„œλ“œλ„ Promiseλ₯Ό λ°˜ν™˜.
  • 주둜 비동기 μ΄ˆκΈ°ν™”, μ„œλ²„ μš”μ²­, DB 호좜 λ“±μ—μ„œ 자주 μ‚¬μš©λ¨.

λͺ¨λ‘ Promise λ₯Ό λ°˜ν™˜ν•œλ‹€λŠ” 점은 동일, μ°¨μ΄λŠ” μ„ μ–Έ μœ„μΉ˜μ™€ 문법 ν˜•νƒœμ—λ§Œ μžˆλ‹€.

즉, asyncλ₯Ό 어디에 뢙이든 κ·Έ ν•¨μˆ˜λŠ” ‘항상 비동기 ν•¨μˆ˜’둜 λ™μž‘

 

2. await ν‚€μ›Œλ“œ

await λ“±μž₯ 이유

PromiseλŠ” 비동기이기 λ•Œλ¬Έμ— .then()을 써야 κ²°κ³Όλ₯Ό 얻을 수 μžˆλ‹€.

foo().then(v => console.log(v));

이걸 맀번 .then()으둜 μ“°λ©΄ 가독성이 λ‚˜λΉ μ§€λ―€λ‘œ, await이 λ“±μž₯

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

 

μ™œ await은 async ν•¨μˆ˜ μ•ˆμ—μ„œλ§Œ μ“Έ 수 μžˆλ‚˜?

  • await은 비동기 ν•¨μˆ˜μ˜ 흐름을 μΌμ‹œ 쀑단 μ‹œν‚€λŠ” κΈ°λŠ₯이기 λ•Œλ¬Έ

λ§Œμ•½ 일반 ν•¨μˆ˜μ—μ„œ await을 μ‚¬μš©μ„ ν—ˆμš©ν•˜λ©΄ 동기 μ½”λ“œ 흐름이 깨져버리기 λ•Œλ¬Έμ— μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” λ¬Έλ²•μ μœΌλ‘œ 막아둠

// ❌ SyntaxError
function foo() {
  const data = await fetch(...); // 일반 ν•¨μˆ˜μ—μ„  λΆˆκ°€λŠ₯
}
const getGithubUserName = async id => {
    const res = await fetch(`https://api.github.com/users/${id}`); // (1)
    const { name } = await res.json();  // (2)
    console.log(name); // Ungmo Lee
};

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

await ν‚€μ›Œλ“œλŠ” λ‹€μŒ 싀행을 μΌμ‹œ 쀑지 μ‹œμΌ°λ‹€κ°€ ν”„λ‘œλ―ΈμŠ€κ°€ settled μƒνƒœκ°€ 되면 λ‹€μ‹œ 재개

 

⚠️ ν”„λ‘œλ―ΈμŠ€κ°€ settled μƒνƒœκ°€ λ˜μ—ˆλ‹€?

settled :
이제 더 이상 μƒνƒœκ°€ λ°”λ€Œμ§€ μ•ŠλŠ” μ‹œμ 

 

Promise의 μƒνƒœ 3κ°€μ§€

μƒνƒœ μ„€λͺ… λ‹€μŒ 단계

pending λŒ€κΈ° 쀑 — 아직 κ²°κ³Ό(성곡/μ‹€νŒ¨)κ°€ μ •ν•΄μ§€μ§€ μ•ŠμŒ → fulfilled λ˜λŠ” rejected 둜 이동
fulfilled 비동기 μž‘μ—… 성곡(resolve 호좜됨) settled μƒνƒœ
rejected 비동기 μž‘μ—… μ‹€νŒ¨(reject 호좜됨) settled μƒνƒœ

Promiseκ°€ fulfilled(성곡) λ˜λŠ” rejected(μ‹€νŒ¨) 쀑 μ–΄λŠ ν•œμͺ½μœΌλ‘œ κ²°μ •λ˜λ©΄ κ·Έ μ‹œμ λΆ€ν„°λŠ” settled(확정됨) μƒνƒœκ°€ 됨

 

 

 

μ•žμ„  비동기 처리의 κ²°κ³Όλ₯Ό κ°€μ§€κ³  λ‹€μŒ 비동기 처리λ₯Ό μˆ˜ν–‰ν•˜λŠ” ν•¨μˆ˜μ˜ μ˜ˆμ‹œ

async function bar(n) {
    const a = await new Promise(resolve => setTimeout(() => resolve(n), 3000));
    // 두 번째 비동기 처리λ₯Ό μˆ˜ν–‰ν•˜λ €λ©΄ 첫 번째 비동기 처리 κ²°κ³Όκ°€ ν•„μš”ν•˜λ‹€.
    const b = await new Promise(resolve => setTimeout(() => resolve(a + 1), 2000));
    // μ„Έ 번째 비동기 처리λ₯Ό μˆ˜ν–‰ν•˜λ €λ©΄ 두 번째 비동기 처리 κ²°κ³Όκ°€ ν•„μš”ν•˜λ‹€.
    const c = await new Promise(resolve => setTimeout(() => resolve(b + 1), 1000));
    
    console.log([a,b,c]); // [ 1, 2, 3 ]
}

bar(1); // μ•½ 6초 μ†Œμš”λœλ‹€.

 

3. μ—λŸ¬ 처리

비동기 처리λ₯Ό μœ„ν•œ 콜백 νŒ¨ν„΄μ˜ 단점은 μ—λŸ¬ μ²˜λ¦¬κ°€ κ³€λž€

μ—λŸ¬λŠ” 호좜자 λ°©ν–₯으둜 μ „νŒŒ

→ 콜 μŠ€νƒμ˜ μ•„λž˜ λ°©ν–₯으둜 μ „νŒŒ

async function a() {
  b();
}
function b() {
  throw new Error('μ—λŸ¬!');
}
a();

 

a() → b() → Error λ°œμƒ

bλ₯Ό ν˜ΈμΆœν•œ μͺ½μΈ a μͺ½μœΌλ‘œ μ—λŸ¬κ°€ μ „νŒŒλ˜μ–΄ κ²°κ΅­ μ „μ—­μ—μ„œ Uncaught Error κ°€ 작힘

그런데 setTimeout은 비동기

try {
  setTimeout(() => { throw new Error('Error!'); }, 1000);
} catch (e) {
  console.error('μΊμΉ˜ν•œ μ—λŸ¬', e);
}

 

겉보기엔 try...catchκ°€ μžˆμœΌλ‹ˆ μ—λŸ¬κ°€ 작힐 것 κ°™μ§€λ§Œ,

μ‹€μ œλ‘œλŠ” catch둜 μ•ˆ λ“€μ–΄μ˜΅λ‹ˆλ‹€.

→ 콜 μŠ€νƒμ΄ λΆ„λ¦¬λ˜κΈ° λ•Œλ¬Έ

  • try...catchλŠ” ν˜„μž¬ μ‹€ν–‰ 쀑인 μŠ€νƒ μ•ˆμ—μ„œλ§Œ μœ νš¨ν•©λ‹ˆλ‹€.
  • setTimeout의 μ½œλ°±μ€ ν˜„μž¬ μŠ€νƒμ΄ λλ‚œ ν›„,
  • λ‚˜μ€‘μ— “이벀트 루프”λ₯Ό 톡해 μƒˆλ‘œ μ‹€ν–‰λ˜λŠ” ν•¨μˆ˜
1. try 블둝 μ‹€ν–‰ μ‹œμž‘
2. setTimeout 등둝 (μ½œλ°±μ€ 아직 μ‹€ν–‰ μ•ˆ 됨)
3. try 블둝 μ’…λ£Œ → catch 블둝도 사라짐
4. 1초 ν›„ setTimeout 콜백이 싀행됨 (μƒˆλ‘œμš΄ μŠ€νƒ)
5. 콜백 λ‚΄λΆ€μ—μ„œ Error λ°œμƒ → 이미 try...catch λ²”μœ„ λ°–μž„
Uncaught Error: Error!

 

 

비동기 ν•¨μˆ˜μ˜ 콜백 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•œ 것은 비동기 ν•¨μˆ˜κ°€ μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— try...catch 문을 μ‚¬μš©ν•΄ μ—λŸ¬λ₯Ό μΊμΉ˜ν•  수 μ—†λ‹€.

  • setTimeout μžμ²΄λŠ” 비동기 ν•¨μˆ˜μ΄μ§€λ§Œ,
  • μ½œλ°±μ„ μ‹€ν–‰μ‹œν‚€λŠ” μ£Όμ²΄λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ μ—”μ§„μ˜ 이벀트 루프이기 λ•Œλ¬Έ

즉, 콜백이 싀행될 λ•ŒλŠ” try λΈ”λ‘μ˜ λ¬Έλ§₯이 이미 사라진 μƒνƒœλΌ κ·Έ μ•ˆμ—μ„œ λ°œμƒν•œ μ—λŸ¬λŠ” 더 이상 catch둜 μ „νŒŒλ˜μ§€ λͺ»ν•¨

 

λΉ„λ™κΈ°μ½œλ°± λ‚΄λΆ€μ˜ μ—λŸ¬λ₯Ό 작고 μ‹Άλ‹€λ©΄ 콜백 λ‚΄λΆ€μ—μ„œ 직접 try…catch

setTimeout(() => {
  try {
    throw new Error('Error!');
  } catch (e) {
    console.error('μ—λŸ¬ 작음:', e);
  }
}, 1000);

728x90
'πŸ’› Frontend/πŸ’› Frontend : JavaScript' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€
  • [JavaScript] ν…μŠ€νŠΈ ν•„λ“œμ— μž…λ ₯ν•œ 값을 화면에 μΆ”κ°€ν•˜κ³  μ‚­μ œν•˜κΈ° (νˆ¬λ‘λ¦¬μŠ€νŠΈ)
  • [Javascript] λ²„νŠΌ ν•˜λ‚˜λ‘œ 닀크 λͺ¨λ“œ μ„€μ •ν•˜κΈ° (toggle)
eyes from es
eyes from es
  • eyes from es
    eyes from es
    eyes from es
  • 전체
    였늘
    μ–΄μ œ
    • λΆ„λ₯˜ 전체보기
      • ❀️ κΏ€νŒ λͺ¨μŒ
        • ❀️ 갓생 κΏ€νŒ
        • ❀️ ν”„λ‘œκ·Έλž˜λ°
      • 🧑 Projects
        • 🧑 Projects: Web
        • 🎀Preterview
        • 🧑 Projects: App
        • πŸ§‘λŒ€μ™Έν™œλ™
        • 🧑 OSCCA μ˜€ν”ˆμ†ŒμŠ€ μ»¨νŠΈλ¦¬λ·°μ…˜ 아카데미
      • πŸ’› Frontend
        • πŸ’› Frontend : React
        • πŸ’› Frontend : JavaScript
        • πŸ’› Frontend : TypeScript
      • πŸ’š Backend
      • πŸ’™ OS: 운영체제
        • πŸ’™ Linux
      • πŸ’œ μ½”λ”©ν…ŒμŠ€νŠΈ
        • πŸ’œ 자료ꡬ쑰
        • πŸ’œ μ•Œκ³ λ¦¬μ¦˜
        • πŸ’œ λ°±μ€€
        • πŸ’œSWEA
        • πŸ’œν”„λ‘œκ·Έλž˜λ¨ΈμŠ€
      • πŸ”΄ Study
        • πŸ”΄λ©΄μ ‘ μŠ€ν„°λ””
        • πŸ”΄ 기업뢄석
        • πŸ”΄ μ—λŸ¬λ…ΈνŠΈ(Error Note)🧱
        • πŸ”΄ ITNews(Coding)
        • πŸ”΄ ITNews(Tech)
      • 🟠 인생 κ³„νš
        • 🟠 μ˜¬ν•΄ λͺ©ν‘œ
      • 🟑 TIL
        • 🟑 TIL 일기
  • λΈ”λ‘œκ·Έ 메뉴

    • ν™ˆ
    • νƒœκ·Έ
    • λ°©λͺ…둝
  • 링크

  • 곡지사항

  • 인기 κΈ€

  • νƒœκ·Έ

    λ‰΄μŠ€λ£Έ
    동ν–₯뢄석
    μ›Ήκ°œλ°œ
    슀파λ₯΄νƒ€μ½”λ”©ν΄λŸ½
    μ½”ν…Œ
    Ai
    자료ꡬ쑰
    μ‚Όμ„±μ „μž
    μŠ€λ§ˆνŠΈμ‹±μŠ€
    μ•Œκ³ λ¦¬μ¦˜
    css
    μ½”λ”©
    기업뢄석
    κ°œλ°œκ³΅λΆ€
    λ°±μ€€
    졜근이슈
    C
    html
    μ½”λ“œλ¦¬λ·°
    넀카라쿠배
    λ‰΄μŠ€μŠ€ν¬λž©
    개발
    μŠ€ν„°λ””
    μ½”λ“œμŠ€ν„°λ””
    λΆ„μ„λ ˆν¬νŠΈ
    μ½”λ”©ν…ŒμŠ€νŠΈ
    SW이슈
    IT이슈
    λ¬Έμ œν’€μ΄
    λ°©ν•™μŠ€ν„°λ””
  • 졜근 λŒ“κΈ€

  • 졜근 κΈ€

  • hELLOΒ· Designed Byμ •μƒμš°.v4.10.5
eyes from es
[JS] μ œλ„ˆλ ˆμ΄ν„°μ™€ async/await
μƒλ‹¨μœΌλ‘œ

ν‹°μŠ€ν† λ¦¬νˆ΄λ°”