๋ฐ˜์‘ํ˜•

์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋Š” ES6์— ๋„์ž…๋œ ํŠน์ˆ˜ํ•œ ํ•จ์ˆ˜๋‹ค. ํ•จ์ˆ˜ ํ˜ธ์ถœ์ž๊ฐ€ ํ•จ์ˆ˜ ์‹คํ–‰์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ณ , ํ•จ์ˆ˜ ํ˜ธ์ถœ์ž์™€ ํ•จ์ˆ˜ ์ƒํƒœ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜๋„ ์žˆ๋‹ค. ์ด๋Ÿฐ ํŠน์ง• ๋•Œ๋ฌธ์— ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์—์„  ์ฝ”๋“œ ๋ธ”๋ก์˜ ์‹คํ–‰์„ ์ž ์‹œ ๋ฉˆ์ท„๋‹ค๊ฐ€ ํ•„์š”ํ•œ ์‹œ์ ์— ์žฌ๊ฐœํ•  ์ˆ˜ ์žˆ๋‹ค. ์ผ๋ฐ˜ ํ•จ์ˆ˜๋Š” 0~1๊ฐœ ๊ฐ’๋งŒ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ ๊ฐ’์„ ํ•„์š”์— ๋”ฐ๋ผ ํ•˜๋‚˜์”ฉ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ ํŠน์ง•


  1. ํ•จ์ˆ˜ ํ˜ธ์ถœ์ž์—๊ฒŒ ํ•จ์ˆ˜ ์‹คํ–‰์˜ ์ œ์–ด๊ถŒ์„ ์–‘๋„(yield)ํ•  ์ˆ˜ ์žˆ๋‹ค
    • ์ผ๋ฐ˜ ํ•จ์ˆ˜ : ํ•จ์ˆ˜ ํ˜ธ์ถœ์ž(caller)๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ ์ดํ›„ ํ•จ์ˆ˜ ์‹คํ–‰์„ ์ œ์–ดํ•  ์ˆ˜ ์—†๋‹ค.
    • ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜ : ํ•จ์ˆ˜ ํ˜ธ์ถœ์ž๊ฐ€ ํ•จ์ˆ˜ ์‹คํ–‰์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค(ํ•จ์ˆ˜ ์‹คํ–‰ ์ผ์‹œ ์ •์ง€ / ์žฌ๊ฐœ)
  2. ํ•จ์ˆ˜ ํ˜ธ์ถœ์ž์™€ ํ•จ์ˆ˜ ์ƒํƒœ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค
    • ์ผ๋ฐ˜ ํ•จ์ˆ˜ : ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ์ „๋‹ฌ๋ฐ›๊ณ  ํ•จ์ˆ˜ ์ฝ”๋“œ๋ฅผ ์ผ๊ด„ ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ๊ฐ’์„ ์™ธ๋ถ€๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
    • ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜ : ํ•จ์ˆ˜ ํ˜ธ์ถœ์ž์—๊ฒŒ ์ƒํƒœ๋ฅผ ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜, ํ•จ์ˆ˜ ํ˜ธ์ถœ์ž๋กœ๋ถ€ํ„ฐ ์ƒํƒœ๋ฅผ ์ „๋‹ฌ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.
  3. ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜ ์ •์˜ ๋ฐฉ๋ฒ•


๐Ÿ’ก ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋‹ค. ๋”ฐ๋ผ์„œ ํ•จ์ˆ˜ ์ž์ฒด์— ์ „๊ฐœ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋Š” function* ํ‚ค์›Œ๋“œ๋กœ ์„ ์–ธํ•˜๊ณ  ํ•จ์ˆ˜ ๋ณธ๋ฌธ์—” 1๊ฐœ ์ด์ƒ์˜ yield ํ‘œํ˜„์‹์„ ํฌํ•จํ•œ๋‹ค. ๋‚˜๋จธ์ง„ ์ผ๋ฐ˜ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•˜๋‹ค. * ๊ธฐํ˜ธ๋Š” ์• ์Šคํ„ฐ๋ฆฌ์Šคํฌ(Asterisk)๋ผ๊ณ  ๋ถ€๋ฅด๋ฉฐ function ํ‚ค์›Œ๋“œ์™€ ํ•จ์ˆ˜ ์ด๋ฆ„ ์‚ฌ์ด๋ผ๋ฉด ์–ด๋””์— ๋ถ™์—ฌ๋„ ์ƒ๊ด€์—†๋‹ค. ๋Œ€๋ถ€๋ถ„์€ function ํ‚ค์›Œ๋“œ ๋ฐ”๋กœ ๋’ค์— ๋ถ™์ธ๋‹ค. ex) function*

// ์„ ์–ธ์‹
function* genDecFunc() {
  yield 1;
}

// ํ‘œํ˜„์‹
const genExpFunc = function* () {
  /* ... */
};

// ๊ฐ์ฒด ๋ฉ”์„œ๋“œ
const obj = {
  *genObjMethod() {
    /* ... */
  },
};

// ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ
class MyClass {
  *genClsMethod() {
    /* ... */
  }
}

 

โ—๏ธ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋Š” ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋กœ ์ •์˜ํ•  ์ˆ˜ ์—†๊ณ , new ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๋‹ค.

const genArrowFunc = * () => { /* ... */ } // Error! Unexpected token '*'

function* genFunc() { /* ... */ }
new genFunc(); // Error! genFunc is not a constructor

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜ ์ž์ฒด๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ฏ€๋กœ ์•„๋ž˜์ฒ˜๋Ÿผ ์ „๊ฐœ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

function* generateSequence() {
  yield 1;
  yield 2;
  yield 3;
}
const res = [0, ...generateSequence()]; // [0, 1, 2, 3]

console.log(Symbol.iterator in generateSequence.prototype); // true
// ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋Š” Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์†๋ฐ›์œผ๋ฏ€๋กœ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋‹ค

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋Š” Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์†๋ฐ›์œผ๋ฏ€๋กœ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋‹ค.

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด


๐Ÿ’ก ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ”(iterable)์ด๋ฉด์„œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ(iterator)๋‹ค.

 

์ผ๋ฐ˜ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํ•จ์ˆ˜์˜ ์ฝ”๋“œ ๋ธ”๋ก์„ ์‹คํ–‰ํ•œ๋‹ค. ๋ฐ˜๋ฉด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ ํ›„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋Š” Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์† ๋ฐ›๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ฉด์„œ value, done ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” next ๋ฉ”์„œ๋“œ๋ฅผ ์†Œ์œ ํ•˜๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋‹ค.

// ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜ ์ •์˜
function* genFunc() {
  yield 1;
  yield 2;
  yield 3;
}

// ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด ๋ฐ˜ํ™˜
// ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ฉด์„œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋‹ค
const generator = genFunc();
console.log(Symbol.iterator in generator); // true (์ดํ„ฐ๋Ÿฌ๋ธ”)
console.log('next' in generator); // true (์ดํ„ฐ๋ ˆ์ดํ„ฐ)

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋Š” next ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ–๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ์ง€๋งŒ, ์ดํ„ฐ๋ ˆ์ดํ„ฐ์—๋Š” ์—†๋Š” return, throw ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ–๋Š”๋‹ค. ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด์˜ next, return, throw ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ๋™์ž‘ํ•œ๋‹ค.

function* genFunc() {
  try {
    yield 1;
    yield 2;
    yield 3;
  } catch (e) {
    console.error(e);
  }
}

const generator = genFunc();
generator.next(); // {value: 1, done: false}
generator.return('End'); // {value: 'End', done: true}
generator.throw('Error'); // {value: undefined, done: true}

 

  1. next ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
    ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ yield ํ‘œํ˜„์‹๊นŒ์ง€ ์ฝ”๋“œ ๋ธ”๋ก ์‹คํ–‰ํ•˜๊ณ , yield๋œ ๊ฐ’์„ value ํ”„๋กœํผํ‹ฐ ๊ฐ’์œผ๋กœ, false๋ฅผ done ํ”„๋กœํผํ‹ฐ ๊ฐ’์œผ๋กœ ๊ฐ–๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด ๋ฐ˜ํ™˜.
  2. return ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
    ์ธ์ž๋กœ ์ „๋‹ฌ๋ฐ›์€ ๊ฐ’์„ value ํ”„๋กœํผํ‹ฐ ๊ฐ’์œผ๋กœ, true๋ฅผ done ํ”„๋กœํผํ‹ฐ ๊ฐ’์œผ๋กœ ๊ฐ–๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด ๋ฐ˜ํ™˜.
  3. throw ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
    ์ธ์ž๋กœ ์ „๋‹ฌ๋ฐ›์€ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  undefined๋ฅผ value ํ”„๋กœํผํ‹ฐ ๊ฐ’์œผ๋กœ, true๋ฅผ done ํ”„๋กœํผํ‹ฐ ๊ฐ’์œผ๋กœ ๊ฐ–๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด ๋ฐ˜ํ™˜

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ์ผ์‹œ ์ค‘์ง€์™€ ์žฌ๊ฐœ


์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋Š” yield ํ‚ค์›Œ๋“œ์™€ next ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ์‹คํ–‰์„ ์ž ์‹œ ์ค‘์ง€ํ–ˆ๋‹ค๊ฐ€ ํ•„์š”ํ•œ ์‹œ์ ์— ๋‹ค์‹œ ์žฌ๊ฐœํ•  ์ˆ˜ ์žˆ๋‹ค. ์ผ๋ฐ˜ ํ•จ์ˆ˜๋Š” ํ˜ธ์ถœ ์ดํ›„ ํ•จ์ˆ˜๊ฐ€ ์ œ์–ด๊ถŒ์„ ๋…์ ํ•˜์ง€๋งŒ, ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋Š” ํ•จ์ˆ˜ ํ˜ธ์ถœ์ž์—๊ฒŒ ์ œ์–ด๊ถŒ์„ ์–‘๋„ํ•ด์„œ ํ•„์š”ํ•œ ์‹œ์ ์— ํ•จ์ˆ˜ ์‹คํ–‰์„ ์žฌ๊ฐœํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด์— ์žˆ๋Š” next ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ ์ฝ”๋“œ ๋ธ”๋ก์„ yield ํ‘œํ˜„์‹๊นŒ์ง€๋งŒ ์‹คํ–‰ํ•œ๋‹ค. yield ํ‚ค์›Œ๋“œ๋Š” ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ ์‹คํ–‰์„ ์ผ์‹œ ์ค‘์ง€์‹œํ‚ค๊ฑฐ๋‚˜ yield ํ‚ค์›Œ๋“œ ๋’ค์— ์˜ค๋Š” ํ‘œํ˜„์‹ ํ‰๊ฐ€ ๊ฒฐ๊ณผ๋ฅผ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜ ํ˜ธ์ถœ์ž์—๊ฒŒ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

// ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜ ์ •์˜
function* genFunc() {
  yield 1;
  yield 2;
  yield 3;
}

const generator = genFunc();
// next ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ–๋Š” ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด ๋ฐ˜ํ™˜(์ดํ„ฐ๋Ÿฌ๋ธ”+์ดํ„ฐ๋ ˆ์ดํ„ฐ)

generator.next(); // {value: 1, done: false}
// next ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์ฒซ๋ฒˆ์งธ yield ํ‘œํ˜„์‹๊นŒ์ง€ ์‹คํ–‰ํ•˜๊ณ  ์ผ์‹œ ์ค‘์ง€
// next ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ์ฒด๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด
// value ํ”„๋กœํผํ‹ฐ์—” ์ฒซ๋ฒˆ์งธ yield ํ‘œํ˜„์‹์—์„œ yield๋œ ๊ฐ’ 1 ํ• ๋‹น
// ํ•จ์ˆ˜๋ฅผ ๋๊นŒ์ง€ ์‹คํ–‰ํ•˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ done ํ”„๋กœํผํ‹ฐ์—” false ํ• ๋‹น

generator.next(); // {value: 2, done: false}
// ๋‘๋ฒˆ์งธ yield ํ‘œํ˜„์‹๊นŒ์ง€ ์‹คํ–‰ํ•˜๊ณ  ์ผ์‹œ ์ค‘์ง€

generator.next(); // {value: 3, done: false}
// ์„ธ๋ฒˆ์งธ yield ํ‘œํ˜„์‹๊นŒ์ง€ ์‹คํ–‰ํ•˜๊ณ  ์ผ์‹œ ์ค‘์ง€

generator.next(); // {value: undefined, done: true}
// ๋‚จ์€ yield ํ‘œํ˜„์‹์ด ์—†์œผ๋ฏ€๋กœ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ ๋งˆ์ง€๋ง‰๊นŒ์ง€ ์‹คํ–‰
// yield ํ‘œํ˜„์‹์ด ์—†์œผ๋ฏ€๋กœ value ํ”„๋กœํผํ‹ฐ์—” undefined ํ• ๋‹น
// ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ๋๊นŒ์ง€ ์‹คํ–‰ํ–ˆ์œผ๋ฏ€๋กœ done ํ”„๋กœํผํ‹ฐ์—” true ํ• ๋‹น

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด์˜ next ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด yield ํ‘œํ˜„์‹๊นŒ์ง€ ์‹คํ–‰ํ•˜๊ณ  ์ผ์‹œ ์ค‘์ง€๋˜๋ฉฐ, ์ด๋•Œ ํ•จ์ˆ˜ ์ œ์–ด๊ถŒ์ด ํ˜ธ์ถœ์ž๋กœ ์–‘๋„๋œ๋‹ค. ์ดํ›„ next ๋ฉ”์„œ๋“œ๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•˜๋ฉด ๋งˆ์ง€๋ง‰ ์ฝ”๋“œ ์‹คํ–‰ ์ง€์ ๋ถ€ํ„ฐ ๋‹ค์Œ yield ํ‘œํ˜„์‹๊นŒ์ง€ ์‹คํ–‰ํ•˜๊ณ  ์ผ์‹œ์ค‘์ง€๋œ๋‹ค. next ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด๋Š” ์•„๋ž˜ ์†์„ฑ์„ ๊ฐ€์ง„๋‹ค.

 

  • value : yield ํ‘œํ˜„์‹์—์„œ yield๋œ ๊ฐ’(yield ํ‚ค์›Œ๋“œ ๋’ค์— ์žˆ๋Š” ๊ฐ’)
  • done : ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ๋๊นŒ์ง€ ์‹คํ–‰ํ–ˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” Boolean ๊ฐ’

 

์œ„ ๊ณผ์ •์„ ์ •๋ฆฌํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

generator.next() → yield → 
generator.next() → yield → 
... →
generator.next() → return

 

next ๋ฉ”์„œ๋“œ์— ๊ฐ’ ์ „๋‹ฌํ•˜๊ธฐ


๐Ÿ’ก ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์—์„œ ๋ฐ˜ํ™˜๊ฐ’์€ ํฐ ์˜๋ฏธ๊ฐ€ ์—†๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์—์„  return ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ, ์ข…๋ฃŒ์˜ ์˜๋ฏธ๋กœ๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.

 

์ด๋ฏธ์ง€ ์ถœ์ฒ˜ JavaScript Info

์ดํ„ฐ๋ ˆ์ดํ„ฐ์˜ next ๋ฉ”์„œ๋“œ์™€ ๋‹ฌ๋ฆฌ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด์˜ next ๋ฉ”์„œ๋“œ๋Š” ์ธ์ž๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. next ๋ฉ”์„œ๋“œ๊ฐ€ ์ „๋‹ฌ๋ฐ›์€ ์ธ์ž๋Š” ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ yield ํ‘œํ˜„์‹์„ ํ• ๋‹น๋ฐ›๋Š” ๋ณ€์ˆ˜์— ํ• ๋‹น๋œ๋‹ค. yield ํ‘œํ˜„์‹์„ ํ• ๋‹น๋ฐ›๋Š” ๋ณ€์ˆ˜์—(์•„๋ž˜ ์˜ˆ์‹œ์—์„œ x, y ๋ณ€์ˆ˜) yield ํ‘œํ˜„์‹์˜ ํ‰๊ฐ€ ๊ฒฐ๊ณผ๊ฐ€ ํ• ๋‹น๋˜์ง€ ์•Š๋Š”์ ์— ์ฃผ์˜ํ•œ๋‹ค. ์ฒซ next() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์€ ์ธ์ž๋ฅผ ๋ฐ›์ง€ ์•Š์œผ๋ฏ€๋กœ ์ฃผ์˜ํ•œ๋‹ค. 

function* getFunc() {
  const x = yield 1; // ๋ณ€์ˆ˜ x๋Š” ๋‘๋ฒˆ์งธ next ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๊ฒฐ์ •๋œ๋‹ค
  const y = yield x + 10; // ๋ณ€์ˆ˜ y๋Š” ์„ธ๋ฒˆ์งธ next ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๊ฒฐ์ •๋œ๋‹ค
  return x + y;
}

const generator = getFunc();
// next ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ–๋Š” ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด ๋ฐ˜ํ™˜(์ดํ„ฐ๋Ÿฌ๋ธ”+์ดํ„ฐ๋ ˆ์ดํ„ฐ)

let res = generator.next(); // {value: 1, done: false}
// ์ฒ˜์Œ ํ˜ธ์ถœํ•˜๋Š” next ๋ฉ”์„œ๋“œ์—๋Š” ์ธ์ž๋ฅผ ์ „๋‹ฌํ•˜์ง€ ์•Š๋Š”๋‹ค(์ „๋‹ฌํ•ด๋„ ๋ฌด์‹œ๋œ๋‹ค)
// ์ฒซ๋ฒˆ์งธ yield ํ‘œํ˜„์‹๊นŒ์ง€ ์‹คํ–‰ํ•˜๊ณ  ์ผ์‹œ ์ค‘์ง€๋˜๋ฉฐ, yield๋œ ๊ฐ’ 1์€ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด์˜ value ํ”„๋กœํผํ‹ฐ์— ํ• ๋‹น๋œ๋‹ค
// ์ด ์‹œ์ ์—์„œ x ๋ณ€์ˆ˜์—๋Š” ์•„๋ฌด๊ฒƒ๋„ ํ• ๋‹น๋˜์ง€ ์•Š์•˜๋‹ค. x ๋ณ€์ˆ˜ ๊ฐ’์€ ๋‹ค์Œ next ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๊ฒฐ์ •๋œ๋‹ค

res = generator.next(10); // {value: 20, done: false}
// next ๋ฉ”์„œ๋“œ ์ธ์ž๋กœ ์ „๋‹ฌํ•œ 10์€ getFunc ํ•จ์ˆ˜์˜ x ๋ณ€์ˆ˜์— ํ• ๋‹น๋œ๋‹ค
// next ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด์˜ value ํ”„๋กœํผํ‹ฐ์—๋Š” ๋‘ ๋ฒˆ์งธ yield๋œ ๊ฐ’ 20์ด ํ• ๋‹น๋œ๋‹ค

res = generator.next(20); // {value: 30, done: true}
// next ๋ฉ”์„œ๋“œ ์ธ์ž๋กœ ์ „๋‹ฌํ•œ 20์€ getFunc ํ•จ์ˆ˜์˜ y ๋ณ€์ˆ˜์— ํ• ๋‹น๋œ๋‹ค
// next ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด์˜ value ํ”„๋กœํผํ‹ฐ์—๋Š” ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’ 30์ด ํ• ๋‹น๋œ๋‹ค
// ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ๋๊นŒ์ง€ ์‹คํ–‰ํ–ˆ์œผ๋ฏ€๋กœ done ํ”„๋กœํผํ‹ฐ์—” true๊ฐ€ ํ• ๋‹น๋œ๋‹ค

 

์ด์ฒ˜๋Ÿผ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์—์„  next ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด yield ํ‘œํ˜„์‹๊นŒ์ง€ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œ์ผœ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ์ƒํƒœ(yield๋œ ๊ฐ’)๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜, next ๋ฉ”์„œ๋“œ์— ์ธ์ž๋ฅผ ์ „๋‹ฌํ•ด์„œ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด์— ์ƒํƒœ(yield ํ‘œํ˜„์‹์„ ํ• ๋‹น๋ฐ›๋Š” ๋ณ€์ˆ˜) ๊ฐ’์„ ์ฃผ์ž…ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ์˜ ํ™œ์šฉ


์ดํ„ฐ๋Ÿฌ๋ธ” ๊ตฌํ˜„

์•„๋ž˜ range ๋ณ€์ˆ˜๋Š” ์ˆซ์ž ๊ฐ„๊ฒฉ์„ from(1)๊ณผ to(5) ์†์„ฑ์œผ๋กœ ๋‚˜ํƒ€๋‚ด๊ณ  ์žˆ๋Š” ์ผ๋ฐ˜์ ์ธ ๊ฐ์ฒด๋‹ค. ์ผ๋ฐ˜ ๊ฐ์ฒด๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ”์ด ์•„๋‹ˆ๋ฏ€๋กœ ๋ฐ˜๋ณต๋ฌธ์„ ๋Œ๋ฆด ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ๋ฐ˜๋ณต ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด๋กœ ๋งŒ๋“ค์—ˆ๋‹ค. — ์ดํ„ฐ๋Ÿฌ๋ธ”๊ณผ ๊ด€๋ จํ•œ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋งํฌ ์ฐธ๊ณ 

// ์ฝ”๋“œ ์ฐธ๊ณ  JavaScript Info
const range = {
  from: 1,
  to: 5,

  // for..of ์ตœ์ดˆ ํ˜ธ์ถœ ์‹œ, Symbol.iterator๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
  [Symbol.iterator]() {
    // Symbol.iterator๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
    // for..of๋Š” ๋ฐ˜ํ™˜๋œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋งŒ์„ ๋Œ€์ƒ์œผ๋กœ ๋™์ž‘ํ•˜๊ณ , ์ด๋•Œ ๋‹ค์Œ ๊ฐ’๋„ ์ •ํ•ด์ง„๋‹ค.
    return {
      current: this.from,
      last: this.to,

      // for..of ๋ฐ˜๋ณต๋ฌธ์— ์˜ํ•ด ๊ฐ ์ดํ„ฐ๋ ˆ์ด์…˜๋งˆ๋‹ค next()๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
      next() {
        // next()๋Š” ๊ฐ์ฒด ํ˜•ํƒœ์˜ ๊ฐ’, {done:.., value :...}์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ๋œ๋‹ค.
        if (this.current <= this.last) {
          return { done: false, value: this.current++ };
        }
        return { done: true };
      },
    };
  },
};

console.log([...range]); // [1, 2, 3, 4, 5]

 

Symbol.iterator ๋Œ€์‹  ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋กœ ๋ฐ˜๋ณตํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ™์€ range ๊ฐ์ฒด์ง€๋งŒ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋” ๊น”๋”ํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

const range = {
  from: 1,
  to: 5,
  *[Symbol.iterator]() {
    for (let value = this.from; value <= this.to; value++) {
      yield value;
    }
  },
};

console.log([...range]); // [1, 2, 3, 4, 5]

 

ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ตฌํ˜„

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•ด ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹๋ณด๋‹ค ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜๋Š” ์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜์—ฌ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด์„ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ ์ดํ•ด๊ฐ€ ์ž˜ ์•ˆ๋œ๋‹ค๋ฉด ์ดํ„ฐ๋Ÿฌ๋ธ” ํฌ์ŠคํŒ…์„ ์ฐธ๊ณ ํ•˜๋ฉด ์ข‹๋‹ค. 

// ์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•ด์„œ ๋ฌดํ•œ ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜
// infiniteFibonacci์—” ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด๊ฐ€ ๋‹ด๊ธด๋‹ค {next: ƒ, Symbol(Symbol.iterator): ƒ}
const infiniteFibonacci = (function () {
  let [pre, cur] = [0, 1];

  return {
    // ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด ๋ฐ˜ํ™˜
    [Symbol.iterator]() {
      return this;
    },
    next() {
      [pre, cur] = [cur, pre + cur];
      return { value: cur }; // ๋ฌดํ•œ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ฏ€๋กœ done ํ”„๋กœํผํ‹ฐ๋ฅผ ์ƒ๋žตํ•œ๋‹ค
    },
  };
})();

// for of ๋ฌธ์„ ์‹œ์ž‘ํ•˜๋ฉด Symbol.iterator ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค
// ์ˆœํšŒ๋ฅผ ์‹œ์ž‘ํ•˜๋ฉด ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด์— ์žˆ๋Š” next ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค
// ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด์˜ value ํ”„๋กœํผํ‹ฐ ๊ฐ’์€ for of ๋ฌธ์˜ ๋ณ€์ˆ˜์— ํ• ๋‹น๋œ๋‹ค.
// ์ˆœํšŒ๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด์˜ done ํ”„๋กœํผํ‹ฐ๊ฐ€ true ์ผ๋•Œ๊นŒ์ง€ ๊ณ„์†๋œ๋‹ค.
// ํ•˜์ง€๋งŒ ์œ„์—์„œ ๊ตฌํ˜„ํ•œ ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด๋Š” done ์†์„ฑ์ด ์—†์œผ๋ฏ€๋กœ ๋ฌดํ•œ ๋ฐ˜๋ณตํ•œ๋‹ค
for (const fiboNum of infiniteFibonacci) {
  if (fiboNum > 30) break;
  console.log(fiboNum); // 1, 2, 3, 5, 8, 13, 21
}

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์œ„๋ณด๋‹ค ๋” ๊น”๋”ํ•˜๊ฒŒ ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด ์ž์ฒด๊ฐ€ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด์ž ์ดํ„ฐ๋ ˆ์ดํ„ฐ์ด๋ฏ€๋กœ, Symbol.iterator, next ๋ฉ”์„œ๋“œ๊ฐ€ ํฌํ•จ๋œ ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด๋ฅผ ๋”ฐ๋กœ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

const infiniteFibonacci = (function* () {
  let [pre, cur] = [0, 1];

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

for (const fiboNum of infiniteFibonacci) {
  if (fiboNum > 30) break;
  console.log(fiboNum); // 1, 2, 3, 5, 8, 13, 21
}

 

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ โญ๏ธ

๐Ÿ’ก ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด์„œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ๋™๊ธฐ ์ฒ˜๋ฆฌ์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๋„ˆ๋ฌด ์žฅํ™ฉํ•ด์ง€๊ณ  ๊ฐ€๋…์„ฑ๋„ ๋–จ์–ด์ง„๋‹ค. ES8(ES 2017)์— ๋„์ž…๋œ async/await ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ๊ฐ€์žฅ ๊น”๋”ํ•˜๋‹ค.

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋Š” next ๋ฉ”์„œ๋“œ์™€ yield ํ‘œํ˜„์‹์„ ์ด์šฉํ•ด ํ•จ์ˆ˜ ํ˜ธ์ถœ์ž(caller)์™€ ํ•จ์ˆ˜์˜ ์ƒํƒœ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฐ ํŠน์„ฑ์„ ํ™œ์šฉํ•ด ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์‚ฌ์šฉํ•œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ then, catch, finally ๊ฐ™์€ ํ”„๋กœ๋ฏธ์Šค ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ ์—†์ด ๋™๊ธฐ ์ฒ˜๋ฆฌ์ฒ˜๋Ÿผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

// ๊ด„ํ˜ธ ๋ฒˆํ˜ธ๋Š” ์ž‘๋™ ์ˆœ์„œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค
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}
})(); // โ‘ท

 

์œ„ ์ฝ”๋“œ๋Š” ์•„๋ž˜ ์ˆœ์„œ๋Œ€๋กœ ๋™์ž‘ํ•œ๋‹ค.

 

  1. ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ async ํ•จ์ˆ˜ ํ˜ธ์ถœ(1). async ํ•จ์ˆ˜ ๋‚ด์—์„  ์ธ์ž๋กœ ๋ฐ›์€ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ด์„œ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ(2)ํ•˜๊ณ  onResolved ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜(3)ํ•œ๋‹ค. async ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•œ onResolved ํ•จ์ˆ˜๋Š” ์ฆ‰์‹œ ํ˜ธ์ถœ(4)๋ผ์„œ ๋ฐฉ๊ธˆ ์ƒ์„ฑํ–ˆ๋˜ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด์˜ next ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ(5)ํ•œ๋‹ค.
  2. next ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ(5)ํ•˜๋ฉด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ ์ฒซ๋ฒˆ์งธ yield ๋ฌธ(6)๊นŒ์ง€ ์‹คํ–‰๋œ๋‹ค. next ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด์˜ done ํ”„๋กœํผํ‹ฐ ๊ฐ’์ด false์ด๋ฏ€๋กœ, ์ฒซ๋ฒˆ์งธ yield๋œ fetch ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ํ”„๋กœ๋ฏธ์Šค๊ฐ€(value ์†์„ฑ๊ฐ’), resolveํ•œ Response ๊ฐ์ฒด(๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ)๋ฅผ onResolved ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋„˜๊ฒจ์„œ ์žฌ๊ท€ํ˜ธ์ถœ(7)ํ•œ๋‹ค.
  3. onResolved ํ•จ์ˆ˜๊ฐ€ ์ธ์ž๋กœ ๋ฐ›์€ Response ๊ฐ์ฒด๋ฅผ next ๋ฉ”์„œ๋“œ ์ธ์ž๋กœ ์ „๋‹ฌํ•ด์„œ ํ˜ธ์ถœ(5)ํ•œ๋‹ค. ์ „๋‹ฌํ•œ ์ธ์ž๋Š” ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ response ๋ณ€์ˆ˜(6)์— ํ• ๋‹น๋˜๊ณ  ๋‘๋ฒˆ์งธ yield๋ฌธ(8)๊นŒ์ง€ ์‹คํ–‰๋œ๋‹ค.
  4. next ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด์˜ done ํ”„๋กœํผํ‹ฐ ๊ฐ’์ด false์ด๋ฏ€๋กœ, ๋‘๋ฒˆ์งธ yield๋œ response.json ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ํ”„๋กœ๋ฏธ์Šค๊ฐ€(value ์†์„ฑ๊ฐ’), resolveํ•œ todo ๊ฐ์ฒด๋ฅผ onResolved ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋„˜๊ฒจ์„œ ์žฌ๊ท€ํ˜ธ์ถœ(7)ํ•œ๋‹ค.
  5. onResolved ํ•จ์ˆ˜๊ฐ€ ์ธ์ž๋กœ ๋ฐ›์€ todo ๊ฐ์ฒด๋ฅผ next ๋ฉ”์„œ๋“œ ์ธ์ž๋กœ ์ „๋‹ฌํ•ด์„œ ํ˜ธ์ถœ(5)ํ•œ๋‹ค. ์ „๋‹ฌํ•œ ์ธ์ž๋Š” ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ todo ๋ณ€์ˆ˜(8)์— ํ• ๋‹น๋˜๊ณ , ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๊ฐ€ ๋๊นŒ์ง€ ์‹คํ–‰๋ผ์„œ ์ฝ˜์†”์„ ์ฐ๋Š”๋‹ค.
  6. next ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด์˜ done ํ”„๋กœํผํ‹ฐ ๊ฐ’์ด true ์ด๋ฏ€๋กœ(์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๊ฐ€ ๋๊นŒ์ง€ ์‹คํ–‰๋จ) ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์ธ undefined(value ์†์„ฑ๊ฐ’)๋ฅผ ๋ฐ˜ํ™˜(9)ํ•˜๊ณ  ์ข…๋ฃŒํ•œ๋‹ค.

 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ์ปดํฌ์ง€์…˜


์ œ๋„ˆ๋ ˆ์ดํ„ฐ์˜ ํŠน์ˆ˜ ๋ฌธ๋ฒ•์ธ ์ปดํฌ์ง€์…˜ yield* ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋ฅผ ๋‹ค๋ฅธ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์— ์‚ฝ์ž…(์ž„๋ฒ ๋“œ)ํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜๋Š” start end ๊ฐ’์„ ๋ฐ›์•„ ์—ฐ์†๋œ ์ˆซ์ž๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋‹ค.

function* generateSequence(start, end) {
  for (let i = start; i <= end; i++) yield i;
}

const generator = generateSequence(0, 10);
generator.next(); // {value: 0, done: false}
generator.next(); // {value: 1, done: false}
// ...

 

์œ„ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์ˆซ์ž 0~9(์œ ๋‹ˆ์ฝ”๋“œ 48~57), ์•ŒํŒŒ๋ฒณ ๋Œ€๋ฌธ์ž A~Z(์œ ๋‹ˆ์ฝ”๋“œ 65~90), ์•ŒํŒŒ๋ฒณ ์†Œ๋ฌธ์ž a~z(์œ ๋‹ˆ์ฝ”๋“œ 97~122)๊นŒ์ง€ ์—ฐ์†์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณธ๋‹ค. ์ผ๋ฐ˜ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•œ๋‹ค๋ฉด ํ•จ์ˆ˜๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ ๋งŒ๋“ค๊ณ , ๊ฐ๊ฐ์˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•œ ํ›„ ๋‹ค์‹œ ์กฐํ•ฉํ•ด์•ผ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

yield* ์ง€์‹œ์ž๋Š” ์‹คํ–‰์„ ๋‹ค๋ฅธ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์—๊ฒŒ ์œ„์ž„ํ•œ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ์—์„  generateSequence ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์—๊ฒŒ ์‹คํ–‰์„ ์œ„์ž„ํ•ด์„œ, ์œ„์ž„๋ฐ›์€ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๊ฐ€ ๋ฐ˜๋ณต์„ ์ˆ˜ํ–‰ํ•œ ์‚ฐ์ถœ ๊ฐ’๋“ค์„ ๋ฐ–์œผ๋กœ ์ „๋‹ฌํ•˜๊ณ  ์žˆ๋‹ค.

// ์ปดํฌ์ง€์…˜์„ ์ ์šฉํ•œ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ์˜ˆ์‹œ
function* generateSequence(start, end) {
  for (let i = start; i <= end; i++) yield i;
}

function* generatePasswordCodes() {
  yield* generateSequence(48, 57); // 0..9
  yield* generateSequence(65, 90); // A..Z
  yield* generateSequence(97, 122); // a..z
}

let str = '';
for (const code of generatePasswordCodes()) {
  str += String.fromCharCode(code);
  // fromCharCode ๋ฉ”์„œ๋“œ๋Š” ์œ ๋‹ˆ์ฝ”๋“œ(์•„์Šคํ‚ค์ฝ”๋“œ) ๊ฐ’์„ ๋ฐ›์•„ ํ•ด๋‹นํ•˜๋Š” ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜ํ•œ๋‹ค
  // ์ฒซ๋ฒˆ์งธ ์ปดํฌ์ง€์…˜ : 0 -> 01 -> 012 -> ...
  // ๋‘๋ฒˆ์งธ ์ปดํฌ์ง€์…˜ : ...789A -> ...789AB -> ...789ABC -> ...
  // ์„ธ๋ฒˆ์งธ ์ปดํฌ์ง€์…˜ : ...XYZa -> ...XYZab -> ...XYZabc -> ...
}

console.log(str); // 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
๋”๋ณด๊ธฐ
function* generateAlphaNum() {
  for (let i = 48; i <= 57; i++) yield i; // yield* generateSequence(48, 57);
  for (let i = 65; i <= 90; i++) yield i; // yield* generateSequence(65, 90);
  for (let i = 97; i <= 122; i++) yield i; // yield* generateSequence(97, 122);
}

let str = '';
for (const code of generateAlphaNum()) {
  str += String.fromCharCode(code);
}

console.log(str); // 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

 

์ด์ฒ˜๋Ÿผ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ์ปดํฌ์ง€์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•œ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์˜ ํ๋ฆ„์„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋‹ค๋ฅธ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์—๊ฒŒ ๋„˜๊ธธ ์ˆ˜ ์žˆ๋‹ค. ์ค‘๊ฐ„ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•˜๋Š” ์ถ”๊ฐ€์ ์ธ ๋ฉ”๋ชจ๋ฆฌ๋„ ํ•„์š”ํ•˜์ง€ ์•Š๋Š” ์žฅ์ ๋„ ์žˆ๋‹ค.

 

๋น„๋™๊ธฐ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ


๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

์ผ๋ฐ˜ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ ๋ชจ๋“  ๊ฐ’์€ ๋™๊ธฐ์ ์œผ๋กœ ์ƒ์‚ฐ๋œ๋‹ค. ์ฆ‰, ์ผ๋ฐ˜ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋Š” ๋™๊ธฐ์  ๋ฌธ๋ฒ•์ด๋‹ค. ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์— ๋น„๋™๊ธฐ ์ž‘์—…์„ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ํ•จ์ˆ˜๋ช… ์•ž์— async ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๋ฉด ๋œ๋‹ค. ๊ทธ๋Ÿผ generator.next ๋ฉ”์„œ๋“œ๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด๋ฅผ ํ”„๋กœ๋ฏธ์Šค๋กœ ๊ฐ์‹ธ์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค. next ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด๊ฐ€ ํ”„๋กœ๋ฏธ์Šค์ด๋ฏ€๋กœ ๋ฐ˜๋ณต ์ž‘์—…์„ ํ•  ๋•Œ๋„ await ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ์•ผ ํ•œ๋‹ค. ex) for await ...of

  ๋™๊ธฐ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๋น„๋™๊ธฐ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ(async generator)
์„ ์–ธ ๋ฐฉ๋ฒ• function* async function*
next() ๋ฉ”์„œ๋“œ ๋ฐ˜ํ™˜๊ฐ’ { value: any, done: Boolean } Promise { value: any, done: Boolean }

 

async function* generateSequence(start, end) {
  for (let i = start; i <= end; i++) {
    await new Promise((resolve) => setTimeout(resolve, 1000));
    yield i;
  }
}

(async () => {
  const generator = generateSequence(1, 5);
  for await (const value of generator) console.log(value);
  // 1์ดˆ ๊ฐ„๊ฒฉ์œผ๋กœ 1~5๊นŒ์ง€ ์ถœ๋ ฅ
})();

 

๐Ÿ’ก async ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์—์„œ generator.next() ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•  ๋•Œ๋„ ์•ž์— await ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ์•ผ ํ•œ๋‹ค(next() ๋ฉ”์„œ๋“œ๊ฐ€ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ). await ํ‚ค์›Œ๋“œ๋Š” async ํ•จ์ˆ˜์—์„œ๋งŒ ์ž‘๋™ํ•˜๋Š” ์ ๋„ ์žŠ์ง€ ๋ง๊ฒƒ.

(async () => {
    const generator = generateSequence(1, 5);
    const result = await generator.next(); 
    console.log(result) // {value: 1, done: false}
})();

 

๋น„๋™๊ธฐ ์ดํ„ฐ๋Ÿฌ๋ธ”

์œ„ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ™œ์šฉ ํŒŒํŠธ์—์„œ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋ฅผ ์ด์šฉํ•ด ๋™๊ธฐ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ๊ตฌํ˜„ํ–ˆ์—ˆ๋‹ค.

const range = {
  from: 1,
  to: 5,
  *[Symbol.iterator]() {
    for (let value = this.from; value <= this.to; value++) {
      yield value;
    }
  },
};

console.log([...range]); // [1, 2, 3, 4, 5]

 

Symbol.iterator๋Š” ๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋‹ค. ์œ„์—์„œ ๊ตฌํ˜„ํ•œ ๋™๊ธฐ ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ๋น„๋™๊ธฐ๋กœ ์ž‘๋™ํ•˜๊ฒŒ ํ•˜๋ ค๋ฉด ๋น„๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ดํ„ฐ์ธ Symbol.asyncIterator๋กœ ๋ฐ”๊ฟ”์ฃผ๋ฉด ๋œ๋‹ค.

const range = {
  from: 1,
  to: 5,
  async *[Symbol.asyncIterator]() {
    for (let value = this.from; value <= this.to; value++) {
      await new Promise((resolve) => setTimeout(resolve, 1000));
      yield value;
    }
  },
};

(async () => {
  for await (const value of range) console.log(value);
})(); // 1์ดˆ ๊ฐ„๊ฒฉ์œผ๋กœ 1~5๊นŒ์ง€ ์ถœ๋ ฅ

 

๐Ÿ’ก ์ „๊ฐœ ๋ฌธ๋ฒ•์€ ์ผ๋ฐ˜ ์ดํ„ฐ๋ ˆ์ดํ„ฐ(Symbol.iterator)๊ฐ€ ํ•„์š”ํ•˜๋ฏ€๋กœ ๋น„๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ดํ„ฐ์—์„  ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค.

console.log(...range); // Found non-callable @@iterator

 

ํ™œ์šฉ ์˜ˆ์ œ — ํŽ˜์ด์ง€๋„ค์ด์…˜

๊ฒŒ์‹œํŒ ๊ฐ™์€ ์‚ฌ์ดํŠธ๋Š” ๊ธ€์ด ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— ๋ณดํ†ต ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์ด์šฉํ•œ๋‹ค. ์ด๋•Œ ์„œ๋ฒ„์—์„  ์ผ์ • ์ˆซ์ž ๋‹จ์œ„(ํ•œ ํŽ˜์ด์ง€)๋กœ ๋Š์–ด์„œ ์ •๋ณด๋ฅผ ์ „์†กํ•˜๋Š”๊ฒŒ ์ผ๋ฐ˜์ ์ด๋‹ค. GitHub์˜ ์ปค๋ฐ‹ ์ด๋ ฅ์„ ํ™•์ธํ•  ๋•Œ๋„ ์ด ํŽ˜์ด์ง€๋„ค์ด์…˜์ด ํ™œ์šฉ๋œ๋‹ค.

 

  1. ํด๋ผ์ด์–ธํŠธ๊ฐ€ https://api.github.com/repos/<repo>/commits URL๋กœ ์š”์ฒญ ์ „์†ก
  2. ์„œ๋ฒ„(GitHub)์—์„  30๊ฐœ์˜ ์ปค๋ฐ‹ ์ •๋ณด๊ฐ€ ๋‹ด๊ธด JSON๊ณผ, ๋‹ค์Œ ํŽ˜์ด์ง€์— ๋Œ€ํ•œ Link๋ฅผ Header์— ๋‹ด์•„ ์‘๋‹ต
  3. ๋” ๋งŽ์€ ์ปค๋ฐ‹ ์ •๋ณด(๋‹ค์Œ ํŽ˜์ด์ง€)๊ฐ€ ํ•„์š”ํ•˜๋ฉด ํ—ค๋”์— ๋‹ด๊ธด ๋งํฌ๋ฅผ ์ด์šฉํ•ด ๋‹ค์Œ ์š”์ฒญ ์ „์†ก
  4. ๋ฐ˜๋ณต...

 

๊ตฌํ˜„ ๋ฐฉ๋ฒ•

async ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋ฅผ ์ด์šฉํ•˜๋ฉด ํŽ˜์ด์ง€๋„ค์ด์…˜๊ณผ ๊ด€๋ จํ•œ ์ž‘์—…์„ ์†์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์‹œ์—์„  ์ฒซ๋ฒˆ์งธ ์ปค๋ฐ‹ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ›์•„์˜จ ํ›„(30๊ฐœ ์ปค๋ฐ‹) ๋ฐ˜๋ณต๋ฌธ์„ ํ†ตํ•ด ๋ชจ๋“  ์ปค๋ฐ‹์„ ํ•˜๋‚˜์”ฉ ๋ฐ˜ํ™˜(yield)ํ•˜๋ฉด, ๋‹ค์‹œ while ๋ฌธ์˜ ์ฒ˜์Œ์œผ๋กœ ๋Œ์•„๊ฐ€ ๊ทธ ๋‹ค์Œ ์ปค๋ฐ‹ ๋ฆฌ์ŠคํŠธ(๋‘๋ฒˆ์งธ)๋ฅผ ๋ฐ›์•„์™€์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ž‘์—…์„ ๋ฐ˜๋ณตํ•œ๋‹ค.

// ์ฝ”๋“œ ์ฐธ๊ณ  JavaScript Info
async function* fetchCommits(repo) {
  let url = `https://api.github.com/repos/${repo}/commits`;

  while (url) {
    const response = await fetch(url, {
      // (1) GitHub๋Š” ๋ชจ๋“  ์š”์ฒญ์— user-agent ํ—ค๋”๋ฅผ ๊ฐ•์ œํ•จ
      headers: { 'User-Agent': 'Our script' },
    });

    // (2) ์ปค๋ฐ‹ ์ •๋ณด๊ฐ€ ๋‹ด๊ธด ๋ฐฐ์—ด [{...}, {...}]
    // { author, comments_url, commit, committer, html_url, node_id, parents, sha, url }
    const body = await response.json();

    // (3) ํ—ค๋”์—์„œ ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” URL ์ถ”์ถœ
    let nextPage = response.headers.get('Link').match(/<(.*?)>; rel="next"/);
    nextPage = nextPage?.[1];
    url = nextPage;

    // (4) ํ˜„์žฌ ํŽ˜์ด์ง€๊ฐ€ ๋๋‚  ๋•Œ๊นŒ์ง€ ์ปค๋ฐ‹์„ ํ•˜๋‚˜์”ฉ ๋ฐ˜ํ™˜(yield).
    for (const commit of body) yield commit;
  }
}

(async () => {
  let count = 0;

  for await (const { commit } of fetchCommits('romantech/search-times')) {
    const {
      author: { name, date },
      message,
    } = commit;
    // [Johan/2021-11-14] Merge pull request...
    console.log(`[${name}/${date.match(/(.*?)T/)[1]}] ${message}`);
    if (++count === 100) break; // 100๋ฒˆ์งธ ์ปค๋ฐ‹์—์„œ ๋ฉˆ์ถฅ
  }
})();

 

๋„คํŠธ์›Œํฌ ํƒญ ํ™”๋ฉด. 1ํŽ˜์ด์ง€(commits) ๋ถ€ํ„ฐ ์ˆœ์ฐจ์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๊ณ  ์žˆ๋‹ค

 

์ •๊ทœ์‹์œผ๋กœ URL๋งŒ ์ถ”์ถœํ•˜๊ธฐ โญ๏ธ

response.headers ์‘๋‹ต ํ—ค๋”๋Š” Map๊ณผ ์œ ์‚ฌํ•œ ํ˜•ํƒœ๋กœ ์ €์žฅ๋˜๊ณ , ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ๋„ ๋น„์Šทํ•˜๋‹ค. get ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ Link Header๋ฅผ ์กฐํšŒํ•˜๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ๋˜์–ด ์žˆ๋‹ค. rel=”next” ์™ผ์ชฝ์— ์žˆ๋Š” ์ฃผ์†Œ๊ฐ€ ๋‹ค์Œ ์ปค๋ฐ‹ ๋ฆฌ์ŠคํŠธ๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋Š” ์ฃผ์†Œ๋‹ค.

# response.headers.get('Link') ์กฐํšŒ ๊ฒฐ๊ณผ ์˜ˆ์‹œ
<https://api.github.com/repositories/93253246/commits?page=3>; rel="next",
<https://api.github.com/repositories/93253246/commits?page=196>; rel="last",
<https://api.github.com/repositories/93253246/commits?page=1>; rel="first",
<https://api.github.com/repositories/93253246/commits?page=1>; rel="prev"|

 

<, > ํ™”์‚ด๊ด„ํ˜ธ ์•ˆ์— ์žˆ๋Š” URL๋งŒ ํ•„์š”ํ•˜๋ฏ€๋กœ ์•„๋ž˜์ฒ˜๋Ÿผ ์ •๊ทœ์‹์„ ์‚ฌ์šฉํ•ด์„œ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ดˆ๋ก์ƒ‰ ํ•˜์ด๋ผ์ดํŠธ๋Š” Group ์˜์—ญ, ํŒŒ๋ž€์ƒ‰ ํ•˜์ด๋ผ์ดํŠธ๊นŒ์ง€ ํฌํ•จํ•œ ๋ถ€๋ถ„์ด Match๋œ ์˜์—ญ

  • . ๋ฉ”ํƒ€๋ฌธ์ž : ์ž„์˜ ๋ฌธ์ž
  • * ์ˆ˜๋Ÿ‰์ž : 0๋ฒˆ ์ด์ƒ ์ผ์น˜
  • ? ์ˆ˜๋Ÿ‰์ž : 0๋ฒˆ ๋˜๋Š” 1๋ฒˆ ์ผ์น˜ (๊ธฐ๋ณธ Greedy)
  • ? ์ˆ˜๋Ÿ‰์ž๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ตœ๋Œ€ํ•œ ๋งŽ์€ ๊ฐ’์„ ๋งค์นญ์‹œํ‚ค์ง€๋งŒ(Greedy๋กœ ์ž‘๋™), * ์ˆ˜๋Ÿ‰์ž ๋’ค์— ์‚ฌ์šฉํ•˜๋ฉด(*?) ๊ฐ€์žฅ ์ ์€ ๋ฌธ์ž์—ด์„ ๋งค์นญ์‹œํ‚จ๋‹ค(Lazy๋กœ ์ž‘๋™).
  • <(...)> ์†Œ๊ด„ํ˜ธ๋ฅผ ์ด์šฉํ•ด ๊ทธ๋ฃนํ™”ํ•˜๋ฉด <> ํ™”์‚ด๊ด„ํ˜ธ ์•ˆ์ชฝ์˜ ()์†Œ๊ด„ํ˜ธ๋กœ ๋ฌถ์€ ๊ทธ๋ฃน์ด ๋งค์นญ๋˜๊ณ , ๋งค์นญ๋œ ๊ทธ๋ฃน์€ match ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐฐ์—ด์˜ 1๋ฒˆ์งธ ์ธ๋ฑ์Šค๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
'eeeAiiZuuuuAoooZeeee'.match(/A.*Z/g); // ['AiiZuuuuAoooZ']
// A์™€ Z์‚ฌ์ด ์ž„์˜ ๋ฌธ์ž(.)๊ฐ€ 0๋ฒˆ ์ด์ƒ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ ์ค‘ ์ตœ๋Œ€ํ•œ ๋งŽ์€ ๊ฐ’์œผ๋กœ ๋ฐ˜ํ™˜(Greedy)

'eeeAiiZuuuuAoooZeeee'.match(/A.*?Z/g); // ['AiiZ', 'AoooZ']
// A์™€ Z์‚ฌ์ด ์ž„์˜ ๋ฌธ์ž(.)๊ฐ€ 0๋ฒˆ ์ด์ƒ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ ์ค‘ ์ตœ๋Œ€ํ•œ ์ ์€ ๊ฐ’์œผ๋กœ ๋ฐ˜ํ™˜(Lazy)

'eee<AiiZ>uuuu<AoooZ>eeee'.match(/<(.*?)>/); // ['<AiiZ>', 'AiiZ']
// ๋ฐ˜ํ™˜ํ•œ ๋ฐฐ์—ด์˜ 0๋ฒˆ ์ธ๋ฑ์Šค๋Š” full match๋œ ์˜์—ญ, 1๋ฒˆ ์ธ๋ฑ์Šค๋Š” ์บก์ฒ˜๋ง ๊ทธ๋ฃน ์˜์—ญ
// g ํ”Œ๋ž˜๊ทธ๋ฅผ ๋ถ™์ด๋ฉด "๊ทธ๋ฃน"์„ ํฌํ•จํ•˜์ง€ ์•Š์€ ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ g ํ”Œ๋ž˜๊ทธ๋Š” ๋ถ™์ด์ง€ ์•Š๋Š”๋‹ค
// ์ผ์น˜ํ•˜๋Š” ๋ชจ๋“  ๊ฐ’์„ ์ฐพ์•„์•ผํ•  ๋•(g ํ”Œ๋ž˜๊ทธ๋ฅผ ๋ถ™์—ฌ์•ผํ•˜๋Š” ์ƒํ™ฉ) matchAll ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค

// *? ์ˆ˜๋Ÿ‰์ž๋Š” ๊ฐ€์žฅ ์ ์€ ๊ฐ’์„ ์ฐพ์œผ๋ฏ€๋กœ ์ฒซ๋ฒˆ์งธ <> ํ™”์‚ด๊ด„ํ˜ธ ์•ˆ์ชฝ ์˜์—ญ์ด ๋งค์นญ๋˜๋ฉด ์ฐพ๊ธฐ๋ฅผ ์ข…๋ฃŒํ•จ
// ๋งŒ์•ฝ * ์ˆ˜๋Ÿ‰์ž๋งŒ ๋ถ™์˜€๋‹ค๋ฉด ์ฒซ๋ฒˆ์งธ ํ™”์‚ด๊ด„ํ˜ธ ์•ˆ์ชฝ ์˜์—ญ์ด ๋งค์นญ๋ผ๋„ ๋ฉˆ์ถ”์ง€ ์•Š๊ณ  ์ฐพ๊ธฐ๋ฅผ ๊ณ„์†ํ•ด์„œ,
// ๋งˆ์ง€๋ง‰ > ๋ถ€๋ถ„์ธ ...AoooZ> ๊นŒ์ง€ ์ฐพ๊ธฐ๋ฅผ ๊ณ„์†ํ•จ. ๋”ฐ๋ผ์„œ AIIZ>uuu<AoooZ ๊ฐ€ ๋งค์นญ๋จ

 

  • .*? ํ˜น์€ .+? ์ˆ˜๋Ÿ‰์ž์™€ replace ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํƒœ๊ทธ์˜ ์ฝ˜ํ…์ธ  ๋ถ€๋ถ„๋งŒ ์ถ”์ถœํ•  ์ˆ˜๋„ ์žˆ๋‹ค
const element = '<pre>Hello World</pre>';
const contents = element.replace(/<.+?>/g, ''); // + ์ˆ˜๋Ÿ‰์ž๋Š” 1๋ฒˆ ์ด์ƒ ์ผ์น˜

console.log(contents); // Hello World
console.log(element.match(/<.+?>/g)); // ['<pre>', '</pre>']

 

๋ ˆํผ๋Ÿฐ์Šค


  • <๋ชจ๋˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ Deep Dive> 878p~883p
  • JavaScript Info  

 


๊ธ€ ์ˆ˜์ •์‚ฌํ•ญ์€ ๋…ธ์…˜ ํŽ˜์ด์ง€์— ๊ฐ€์žฅ ๋น ๋ฅด๊ฒŒ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค. ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”

 

๋ฐ˜์‘ํ˜•