// for..of 최초 실행 시, Symbol.iterator가 호출됩니다. [Symbol.iterator]() { // Symbol.iterator메서드는 이터레이터 객체를 반환합니다. // 이후 for..of는 반환된 이터레이터 객체만을 대상으로 동작하는데, // 다음 값은 next()에서 정해집니다. return { current: this.from, last: this.to,
// for..of 반복문에 의해 각 이터레이션마다 next()가 호출됩니다. next() { // (2) // next()는 객체 형태의 값, {done:.., value :...}를 반환합니다. if (this.current <= this.last) { return { done: false, value: this.current++ }; } else { return { done: true }; } }, }; }, };
for (let value of range) { alert(value); // 1, 2, 3, 4, 5 }
이터러블 객체를 비동기적으로 만들기 위한 작업
Symbol.iterator 대신, Symbol.asyncIterator를 사용해야 한다.
next() 는 프라미스를 반환해야 한다.
비동기 이터러블 객체를 대상으로 하는 반복 작업은 for await (let item of iterable) 반복문을 사용해 처리해야 한다.
// for await..of 최초 실행 시, Symbol.asyncIterator가 호출됩니다. [Symbol.asyncIterator]() { // (1) // Symbol.asyncIterator 메서드는 이터레이터 객체를 반환합니다. // 이후 for await..of는 반환된 이터레이터 객체만을 대상으로 동작하는데, // 다음 값은 next()에서 정해집니다. return { current: this.from, last: this.to,
// for await..of 반복문에 의해 각 이터레이션마다 next()가 호출됩니다. asyncnext() { // (2) // next()는 객체 형태의 값, {done:.., value :...}를 반환합니다. // (객체는 async에 의해 자동으로 프라미스로 감싸집니다.)
// 비동기로 무언가를 하기 위해 await를 사용할 수 있습니다. awaitnewPromise((resolve) =>setTimeout(resolve, 1000)); // (3)
(async () => { forawait (let value of range) { // (4) alert(value); // 1,2,3,4,5 } })();
일반 이터레이터와, async 이터레이터에 차이점
객체를 비동기적으로 반복 가능하도록 하려면, Symbol.asyncIterator메서드가 반드시 구현되어야 함.
Symbol.asyncIterator는 프라미스를 반환하는 next()가 구현된 객체를 반환해야 한다.
next() 는 aync메서드일 필요는 없지만 await를 쓰면 편하기 때문에 편의상 이렇게 사용한다.
반복 작업을 하려면 for await를 붙인다. 그럼 range[Symbol.asyncIterator] ()가 일회 호출되는데, 그 이후엔 각 값을 대상으로 next()가 호출된다.
전개 문법 ...은 동기적으로 동작하지 않는다. 동기 작업이 필요한 이터레이터는 Symbol.asyncIterator가 아닌 Symbol.iterator을 찾기 때문이다.
async 제너레이터
일반 제너레이터
1 2 3 4 5 6 7 8 9
function* generateSequence(start, end) { for (let i = start; i <= end; i++) { yield i; } }
for (let value of generateSequence(1, 5)) { alert(value); // 1, then 2, then 3, then 4, then 5 }
async를 붙여주면 비동기적으로 제너레이터를 사용할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
asyncfunction* generateSequence(start, end) { for (let i = start; i <= end; i++) { // await를 사용할 수 있습니다! awaitnewPromise((resolve) =>setTimeout(resolve, 1000));
yield i; } }
(async () => { let generator = generateSequence(1, 5); forawait (let value of generator) { alert(value); // 1, 2, 3, 4, 5 } })();
aync 제너레이의 generator.next()의 메서드는 비동기적이 되고 프라미스를 반환한다. 따라서 await 키워드를 사용해서 generator.next()를 사용하도록 한다.
1
result = await generator.next(); // result = {value: ..., done: true/false}
async 이터러블
반복 가능한 객체를 만들려면 객체에 Symbol.iterator를 추가해야 한다.
1 2 3 4 5 6 7
let range = { from: 1, to: 5, [Symbol.iterator]() { return<range를 반복가능하게 만드는 next가 구현된 객체> } }
일반적으로 제너레이터를 반환하도록 구현하는 경우가 더 많다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
let range = { from: 1, to: 5,
*[Symbol.iterator]() { // [Symbol.iterator]: function*()를 짧게 줄임 for (let value = this.from; value <= this.to; value++) { yield value; } }, };
for (let value of range) { alert(value); // 1, 2, 3, 4, 5 }
지금 이 상태에서 비동기 동작을 축하려면, Symbol.iterator를 async Symbol.asyncIterator로 바꿔야 한다.
async *[Symbol.asyncIterator]() { // [Symbol.asyncIterator]: async function*()와 동일 for (let value = this.from; value <= this.to; value++) { // 값 사이 사이에 약간의 공백을 줌 awaitnewPromise((resolve) =>setTimeout(resolve, 1000));
yield value; } }, };
(async () => { forawait (let value of range) { alert(value); // 1, 2, 3, 4, 5 } })();