πŸ“‹ λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive | 46μž₯ μ œλ„ˆλ ˆμ΄ν„°μ™€ async/await

waterglassesΒ·2022λ…„ 8μ›” 27일
0
post-thumbnail

λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive λ„μ„œμ˜ 46μž₯ μ œλ„ˆλ ˆμ΄ν„°μ™€ async/awaitλ₯Ό μ •λ¦¬ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

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

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

  1. μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” ν•¨μˆ˜ ν˜ΈμΆœμžμ—κ²Œ ν•¨μˆ˜ μ‹€ν–‰μ˜ μ œμ–΄κΆŒμ„ 양도할 수 μžˆλ‹€.
  2. μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” ν•¨μˆ˜ ν˜ΈμΆœμžμ™€ ν•¨μˆ˜μ˜ μƒνƒœλ₯Ό 주고받을 수 μžˆλ‹€.
  3. μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ μ œλ„ˆλ ˆμ΄ν„° 객체λ₯Ό λ°˜ν™˜ν•œλ‹€.

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

function*ν‚€μ›Œλ“œλ‘œ μ„ μ–Έν•œλ‹€. 그리고 ν•˜λ‚˜ μ΄μƒμ˜ yield ν‘œν˜„μ‹μ„ ν¬ν•¨ν•œλ‹€.

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

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

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

// μ œλ„ˆλ ˆμ΄ν„° 클래슀 λ©”μ„œλ“œ
class MyClass {
  * genClsMethod() {
    yield 1;
  }
}
μ œλ„ˆλ ˆμ΄ν„° ν™”μ‚΄ν‘œ ν•¨μˆ˜λ‘œ μ •μ˜ λΆˆκ°€
const genArrowFunc = * () => {
  yield 1;
}// syntaxError: Unexpected token '*'
μ œλ„ˆλ ˆμ΄ν„° new μ—°μ‚°μžμ™€ ν•¨κ»˜ μƒμ„±μž ν•¨μˆ˜λ‘œ 호좜 λΆˆκ°€
function* genFunc() {
  yield 1;
}

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

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

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

μ œλ„ˆλ ˆμ΄ν„° κ°μ²΄λŠ” Symbol.iteratorλ©”μ„œλ“œλ₯Ό μƒμ†λ°›λŠ” μ΄ν„°λŸ¬λΈ”μ΄λ©΄μ„œ value, done ν”„λ‘œνΌν‹°λ₯Ό κ°–λŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” next λ©”μ„œλ“œλ₯Ό μ†Œμœ ν•˜λŠ” μ΄ν„°λ ˆμ΄ν„°λ‹€.

// μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜
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 ν”„λ‘œνΌν‹° κ°’μœΌλ‘œ κ°–λŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜ν•œλ‹€.
// 46-06
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: return}
console.log(generator.throw('Error')); // {value: undefined, done: true}

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

yield ν‚€μ›Œλ“œλŠ” μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜μ˜ 싀행을 μΌμ‹œ 쀑지 μ‹œν‚€κ±°λ‚˜ yield ν‚€μ›Œλ“œ 뒀에 μ˜€λŠ” ν‘œν˜„μ‹μ˜ 평가 κ²°κ³Όλ₯Ό μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜ ν˜ΈμΆœμžμ—κ²Œ λ°˜ν™˜ν•œλ‹€.

function* genFunc() {
  const x = yield 1;
  
  const y = yield (x + 10);
  
  // 일반적으둜 μ œλ„ˆλ ˆμ΄ν„°μ˜ λ°˜ν™˜κ°’μ€ μ˜λ―Έκ°€ μ—†λ‹€.
  // λ”°λΌμ„œ μ œλ„ˆλ ˆμ΄ν„°μ—μ„œλŠ” 값을 λ°˜ν™˜ν•  ν•„μš”κ°€ μ—†κ³  return은 μ’…λ£Œμ˜ 의미둜만 μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.
  return x + y;
}

const generator = genFunc(0);
let res = generator.next();
console.log(res); // {value: 1, done: false}

res = generator.next(10);
console.log(res); // {value: 20, done: true}

res = generator.next(20);
console.log(res); // {value: 30, done: true}

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

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

λ¬΄ν•œ ν”Όλ³΄λ‚˜μΉ˜ μˆ˜μ—΄μ„ μƒμ„±ν•˜λŠ” ν•¨μˆ˜
const infiniteFibonacci = (function () {
  let [pre, cur] = [0, 1];
  
  return {
    [Symbol.iterator]() { return this; },
    next() {
      [pre, cur] = [cur, pre + cur];
      // λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”μ΄λ―€λ‘œ done ν”„λ‘œνΌν‹° μƒλž΅
      return { value: cur };
    }
  }
}());

for (const num of infiniteFibonacci) {
  if (num > 10000) break;
  console.log(num); // 1 2 3 5 8 --
}

μœ„μ˜ ν•¨μˆ˜λ₯Ό μ•„λž˜μ²˜λŸΌ μ‚¬μš©ν•  수 μžˆλ‹€.

const infiniteFibonacci = (function* () {
  let [pre, cur] = [0, 1];
  
  while(true) {
    [pre, cur] = [cur, pre + cur];
    yield cur;
  }
}());

46.5.2 비동기 처리

μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λŠ” ν”„λ‘œλ―ΈμŠ€λ₯Ό μ‚¬μš©ν•œ 비동기 처리λ₯Ό 동기 처리 처럼 κ΅¬ν˜„ν•  수 μžˆλ‹€.

const async = generatorFunc => {
  const generator = generatorFunc(); // 2
  
  const onResolved = arg => {
    const result = generator.next(arg); // 5
    
    return result.done ? result.value : result.value.then(res -> onResolved(res));
  }
  return onResolved;
}

46.6 async/await

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

ν”„λ‘œλ―ΈμŠ€ 기반으둜 λ™μž‘ν•˜λ©° ν”„λ‘œλ―ΈμŠ€μ˜ 후속 처리 λ©”μ„œλ“œ 없이 마치 동기 처리처럼 ν”„λ‘œλ―ΈμŠ€κ°€ 처리 κ²°κ³Όλ₯Ό λ°˜ν™˜ν•˜λ„λ‘ κ΅¬ν˜„ν•  수 μžˆλ‹€.

46.6.1 async ν•¨μˆ˜

async function foo(n) { return n; }
foo(1).then(v => console.log(v)); // 1

const obj = {
  async foo(n) { return n; }
}
obj.foo(4).then(v => console.log(v)); // 4

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

46.6.2 await ν‚€μ›Œλ“œ

await ν‚€μ›Œλ“œλŠ” ν”„λ‘œλ―ΈμŠ€κ°€ settled μƒνƒœ(비동기 μ²˜λ¦¬κ°€ μˆ˜ν–‰λœ μƒνƒœ)κ°€ 될 λ•ŒκΉŒμ§€ λŒ€κΈ°ν•˜λ‹€κ°€ settled μƒνƒœκ°€ 되면 resloveν•œ 처리 κ²°κ³Όλ₯Ό λ°˜ν™˜ν•œλ‹€. λͺ¨λ“  ν”„λ‘œλ―ΈμŠ€μ— await ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 것은 μ£Όμ˜ν•΄μ•Όν•œλ‹€.

46.6.3 μ—λŸ¬ 처리

비동기 처리λ₯Ό μœ„ν•œ 콜백 νŒ¨ν„΄μ˜ 단점 쀑 κ°€μž₯ μ‹¬κ°ν•œ 것은 μ—λŸ¬ μ²˜λ¦¬κ°€ κ³€λž€ν•˜λ‹€λŠ” 것이닀. 즉, 콜 μŠ€νƒμ˜ μ•„λž˜λ°©ν–₯(μ‹€ν–‰ 쀑인 μ»¨ν…μŠ€νŠΈκ°€ ν‘Έμ‹œλ˜κΈ° 직전에 ν‘Έμ‹œλœ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ λ°©ν–₯)으둜 μ „νŒŒλœλ‹€.

ν•˜μ§€λ§Œ 비동기 ν•¨μˆ˜μ˜ μ½œλ°±ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•œ 것은 비동기 ν•¨μˆ˜κ°€ μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— try ... catch 문을 μ‚¬μš©ν•΄ μ—λŸ¬λ₯Ό μΊμΉ˜ν•  수 μ—†λ‹€. ν•˜μ§€λ§Œ async/awaitμ—μ„œ μ—λŸ¬ μ²˜λ¦¬λŠ” try ... catch 문을 μ‚¬μš©ν•  수 μžˆλ‹€. 콜백

async ν•¨μˆ˜ λ‚΄μ—μ„œ catch 문을 μ‚¬μš©ν•΄μ„œ μ—λŸ¬ 처리λ₯Ό ν•˜μ§€ μ•ŠμœΌλ©΄ async ν•¨μˆ˜λŠ” λ°œμƒν•œ μ—λŸ¬λ₯Ό rejectν•˜λŠ” ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•œλ‹€.

Ref

  • 이웅λͺ¨ μ €, ⌜λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive⌟, μœ„ν‚€λΆμŠ€
profile
맀 μˆœκ°„ μ„±μž₯ν•˜λŠ” κ°œλ°œμžκ°€ 되렀고 λ…Έλ ₯ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

0개의 λŒ“κΈ€