프로그래밍 언어에서 iterator는 배열이나 유사한 자료 구조의 내부의 요소를 순회하는 객체이다.
Javascript에서는 ES6에서 Iterable protocol이 추가되었고 iterable, iterator 2가지 형태가 존재한다.
iterable은 객체의 멤버를 반복할 수 있는 객체이다.
Javascript에서는 object property에 Symbol.iterator를 추가해야 한다.
const iterable = new Object();
iterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
console.log([...iterable]); // 1 2 3
for(var value of iterable) {
console.log(value); // 1 2 3
}
iterator는 객체를 next 메서드로 순환 할 수 있는 객체이다. iterator는 next() 메소를 가지고, next 메소드는 아래의 규칙에 따라 구현된다.
done:boolean과 value: any를 포함하는 object를 반환해야 한다.iterator는 next 메소드를 가지고 iterable은 Symbol.iterator 메소드를 가진다.
Javascript에서 generator 객체를 활용하면 iterator를 쉽게 구현할 수 있다.
function* call() {
console.log('first call');
yield 10;
console.log('second call');
yield 20;
console.log('third call');
yield 30;
}
yield : return처럼 함수를 종료한다. 함수를 재 호출(next())할 경우 해당 지점에서 시작한다.
function*은 컨텍스트 상태를 유지하는 함수이며, 호출시 반환자로 Generator 객체를 반환한다.
Generator는 iterator 규칙에 맞는 next() 메서드를 가지고 있기 때문에 iterator 객체이고 return(), throw()를 포함한다.
Generator.next()를 호출하면 generator function의 다음 yield 키워드를 만날때까지 동작하며, 만나면 해당 값을 전달한다.
만약 yield를 만나지 못하고 컨텍스트가 종료되면, { value: undefined, done: true }를 반환한다.
function* generatorFn(a) {
var b = yield 1;
var c = yield 2;
yield a + b + c;
}
var generator = generatorFn(10);
console.log(generator.next(20));
// {value: 1, done: false}
console.log(generator.next(30));
// {value: 2, done: false}
console.log(generator.next(40));
// {value: 80, done: false}
console.log(generator.next(50));
// {value: undefined, done: true}
위의 예시처럼 next 함수에 arguments를 전달하면 yield 키워드에 그 값이 전달된다.
최초의 next arguments는 전달되지 않는데 첫번째 호출때는 yield가 아니기 때문이다.
yield 1에서 재시작하고 b = 30이 된다.yield 2에서 재시작하고 c = 40이 된다.이를 활용해서 함수로 값을 던질 수 있고 이를 이용해서 비동기 콜에서 함수끼리 통신하게 만들 수도 있다고 한다. (어떤 케이스인지는 아직 못찾음)
// without generator
const getSomeDataOfDates = (dates: Date[]) => {
const datas = Promise.all(dates.map(async (date) => {
const res = await someApiCall(date)
return res
}))
return datas
}
// with generator
const generateSomeDataOfDates = async function* (dates: Date[]) => {
for (const date of dates) {
yield someApiCall(date)
}
}
const datas = Promise.all([...generateSomeDataOfDates()])
async-await와 매우 유사한 방법으로 실제로 ES6 polyfill, babel에서 async-await은 Generator로 구현되어 있다고 한다.
Spread 문법을 이용하면 iterable 객체를 해체 할 수 있다.
var text = '123';
console.log([...text]);
// ["1", "2", "3"]
참조
https://pks2974.medium.com/javascript와-iterator-cdee90b11c0f
https://kamang-it.tistory.com/entry/JavaScript-16Generator와-Yield