On a couch

[TIL] Generator 함수 (미완) 본문

프론트엔드 공부/Javascript 읽기

[TIL] Generator 함수 (미완)

couch 2022. 9. 18. 21:20

callback 함수 부분을 읽다가 promise를 설명하면서 generator 함수를 사용하는 것을 보았다.

써 본 적이 없어 낯설었는데, 스터디원 한 분이 좋은 자료를 찾아주셨다!

 

https://dev.to/lydiahallie/javascript-visualized-generators-and-iterators-e36

 

💡🎁 JavaScript Visualized: Generators and Iterators

ES6 introduced something cool called generator functions 🎉 Whenever I ask people about generator func...

dev.to

 

개념

  • generator 함수는 ES6에서 소개되었다.
  • 일반 함수가 run-to-completion 모델(작업이 완료될 때까지 멈추지 않음)을 따르는 반면, generator 함수는 원하는 곳에서 일시정지 시킬 수 있다.

기본 사용법

  • function 키워드 뒤에 * 를 붙여서 생성한다
  • generator 함수를 실행하면 generator object를 반환한다. 이것은 iterator이다.
  • 함수 안에서 yield 키워드를 사용해 실행을 일시중지한다.

yield 키워드의 동작

function* genFunc() {
	yield 'here'
    console.log('First log')
    yield 'there'
    console.log('Second log')
    return 'Done!'
}
  1. 함수를 처음 실행하면, 첫 번째 줄에서 'here'값을 수확(yield)한다
  2. 두 번째로 실행하면, 이전 yield 키워드 줄에서 시작한다. 그 후 두 번째 yield를 만날 때까지 쭉 실행한 다음 'there'값을 수확한다.
  3. 세 번째로 실행하면, 이전 yield 키워드 줄에서 시작한다. return 키워드를 만날 때까지 실행한 후 'Done!'이라는 값을 반환한다.

yield object의 동작

  • 이전번에 어디서 yield했는지에 대한 상태를 기억하려면, 함수를 실행시켜서 변수에 할당해야 한다.
const genObj = genFunc()
  • yieldobject의 프로토타입 체인 상에 next()라는 메소드가 있다. 이걸 처음 실행시키면 yield를 만날 때까지 실행하고, 수확 시 {value : 'here', done: false}를 반환한다.
  • 다시 실행시키면 yield를 만날 때까지 실행하고(console.log('First log')), {value : 'there', done: false}를 수확해 저장한다.
  • 다시 실행시키면 return를 만날 때까지 실행하고(console.log('Second log')), {value : 'Done!', done: true}를 반환해 저장한다.
  • 함수의 iterator는 한 번만 순회 가능하므로, 이미 종료된 상태에서 다시 next() 메소드를 실행하면 계속해서 {value: undefinec, done:true}를 반환한다.

iterator의 활용

  • 함수가 반환하는 yield object는  [Symbol.iterator] 속성을 가졌으므로, 반복 가능한 타입(string, array, object)의 특성을 활용할 수 있다.
  • spread 문법으로 yiled object의 value들을 배열에 담아낼 수 있다. 
  • for...of 문을 활용해 각 yield 값에 원하는 작업을 실행할 수도 있다.
  • [Symbol.iterator] 속성을 가지고 있지 않은 것(순환 가능하지 않은 것)에 수동으로 속성을 부여해서 순환 가능하게 만들 수 있다. 속성값으로는 { value: '...', done: false/true } 형태의 객체를 반환하는 next를 가진 iterator를 할당하면 된다. generator 함수는 기본적으로 iterator를 반환하기 때문에, 간단하게는 generator 함수를 실행해 할당해도 된다.
// 유사배열객체가 아니므로 원래는 순환할 수 없는 객체
const anyObject = {name : 'sol-namoo', adult: true}

// [Symbol.iterator] 속성에 자신을 yield하는 yield object를 할당
anyObject[Symbol.iterator] = function* () {
	yield this
}

iterator의 개념을 어렴풋이 들은 적이 있어서 처음에는 'yield object가 iterator의 특성을 가지고 있다는 뜻이구나' 라고 이해했다.

읽다 보니 yeild object의 형태가 iterator 그 자체였다.

(https://pks2974.medium.com/javascript%EC%99%80-iterator-cdee90b11c0f)

 

예시가 너무 간단해, 이걸 읽는 것만으로는 확실지 않아서 직접 코드를 찍어가면서 확인하려 했더니 생각보다 시간이 든다.

일단 기본적인 것은 이해한 것 같아, 여기까지만 정리해 포스팅한다!