Js에서 Generater란?

이주영·2023년 3월 9일
1

Javascript

목록 보기
7/11
post-thumbnail

들어가기 앞서 🌱

프로젝트를 진행하면서 서버와의 비동기 통신을 하기 위해 fetch API와 HTTP library인 axios를 사용한 경험이 있다. 하지만 async-await를 제대로 알지 못한다는 것을 알았다. async-await을 제대로 알기 위해 JS의 Generator를 학습한 과정을 정리하려고 한다.

제너레이터란

ES6에서 도입된 제너레이터는 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재개할 수 있는 특수한 함수다.

JS에서 제너레이터와 일반함수의 차이

  1. 함수 호출자에게 함수 실행의 제어권을 양도
    함수 호출자가 홈수의 실행권을 가지고 있는 함수가 제너레이터 함수. 함수의 제어권을 함수가 독점하느게 아니라 함수 호출자에게 양도할 수 있다는 것을 의미한다.

  2. 제너레이터 함수는 함수 호출자와 함수의 상태를 주고받을 수 있다.
    일반함수는 외부의 값을 매개변수를 통해서 주입받고 함수의 코드를 실행하여 결과값을 반환하는 형태이다. 즉 함수가 실행되고 있는 동안에는 외부에서 내부로 값을 전달할 수 없다. 하지만 제너레이터 함수는 함수 호출자와 양방향으로 상태를 주고 받을 수 있다.

  3. 제너레이터 함수를 호출하면 제너레이터 객체를 반환한다.

제너레이터의 일시 중지와 재기

yield 식별자를 활용하여 함수 호출자에게 제어권을 양도하고 next 메소드를 통해 함수 내부 블록의 yield표현식까지만 실행한다. 원하는 지점까지 실행시켜 다시 반환하는 식으로 호출과 내부간에 흐름이 생긴다.

제너레이터는 yield 키워드와 next 메서드를 통해서 실행을 일시 중지했다가 필요한 시점에 다시 재개할 수 있다. 제너레이터는 함수 호출자에게 yield(양도)하여 필요한 시점에 함수 실행을 재개한다.

제너레이터 함수를 호출하면 함수의 내부 코드블록이 실행되는게 아니라 제너레이터 객체를 반환한다는데 이터러블이면서 이터레이터인 객체는 next 메소드를 갖는다. 제너레이터 객체의 next 메서드를 호출하면!! 필요한 시점에 함수 실행을 재개할 수 있다.

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

const generator = genFunc();

console.log(generator.next());//{ value: 1, done: false }
console.log(generator.next());//{ value: 2, done: false }
console.log(generator.next());// { value: 3, done: false }
console.log(generator.next());// { value: undefined, done: true }

제너레이터 실행 과정

next() 와 yield 키워드로 함수의 내부와 외부 사이에서 전달되는 방식으로 동작한다

제너레이터 Syntax 정의

  1. function* : Generator 함수 선언 키워드
function* genDecFunc() {
	yield 1;
}

const genExpFunc = function* () {
	yield 1;
};

const obj = {
	*genObjMethod() {
		yield 1;
	},
};

class MyClass {
	*genClsMethod() {
		yield 1;
	}
}

제너레이터 함수는 화살표 함수와 생성자 함수로 호출할 수 없다는 특징이 있다.

  1. yield : next 호출 시 , value로 반환할 값에 사용하는 키워드, 다음 next가 호출 될떄 까지 해당 키워드에서 함수실행이 멈춘다.
function* genFunc() {
	yield 1;
	yield 2;
	yield 3;
}

const generator = genFunc();

console.log(generator); // Object [Generator] {]}

for (const el of generator) {
	console.log(el); // 1 2 3 
}
  1. yield* : 또 다른 iterable 객체를 위임해서 사용하기 위한 키워드
function* generatorFunction(){
	yield* [1,2,3];
}

const generator = generatorFunction();

for (const el of generator) {
	console.log(el)
}

제너레이터 객체

Iteration Interface는 두 가지로 구성된다.

1. iterable 프로토콜

한마디 정리 : Symbol.iterator 메서드를 상속받거나 구현한 객체를 이터러블하다고 한다.
즉, iterable 객체는 iterator 객체를 반환하는 함수를 값으로 갖는 @@iterator 프로퍼티를 포함해야한다. (@@iterator은 Symbol.iterator에서 확인 가능 )

2. iterator 프로토콜

한마디 정리 : value, done 프로퍼티를 갖는 iteratorResult 객체를 반환하는 next 메서드를 소유해야 이터레이터라고 한다. Iterator 객체는 iteratorResult(value, done) 를 반환하는 next 메서드를 포함한다는 특징!!

-> iterator Result
Boolean 타입의 값을 갖는 done 과 모든 타입의 값을 가질 수 있는 value 프로퍼티를 갖는다.

제너레이터의 특징

제너레이터 객체는 next 메서드를 갖는 이터레이터이지만 이터레이터가 없는 throw, return 메소드를 갖는다.

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

const generator = genFunc();

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

제너레이터의 활용

1. 비동기 처리

프로미스의 후속처리 메소드 then/catch/finally 없이 비동기 처리 결과를 반환하도록 구현 가능

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://jsonplaceho";

	const response = yield fetch(url);
	const todo = yield response.json()
	console.log(todo)
})();

async/await

제네레이터로 비동기처리를 하려니 코드가 장황해졌다. 그래서 ES8에 등장한 async/await이 있다.

async/await은 promise 기반으로 동작한다. 프로미스 후속 처리를 할 필요없이 마치 동기 처럼 프로미스를 사용할 수 있다.

에러 처리

콜백함수의 치명적인 단점은 에러 처리가 곤란하다는 것. 에러는 호출자 방향으로 전파된다. 하지만 비동기 함수의 콜백 함수를 호출한 것은 비동기 함수가 아니기 때문에 try-catch문을 사용할 수 없는 문제가 있다.

profile
문제는 비판적으로 삶은 긍정적으로

0개의 댓글