티스토리 뷰

Iteration Protocol

  • ES6에 도입되어 데이터 컬렉션을 순회하기 위한 규칙
  • Iteration Protocol을 준수하면 for.. of, Spread 문법을 사용할 수 있음.
  • Iteration Protocol = Iterable Protocol + Iterator Protocol
const array = [1, 2, 3];
for (const value of array) {
  console.log(value);
}

console.log(...array);

 

Iterable Protocol

Symbol.iterator 메소드를 구현한 객체를 의미한다. (나 순회 할수 있어! 라고 알려주는 척도)

const array = [1, 2, 3];
// iterator가 배열에 존재하는지 여부
console.log(Symbol.iterator in array); // true

for (const value of array) {
  console.log(value); // OK
}


const object = { key: 'value' };
// iterator가 일반 객체에 존재하는지 여부
console.log(Symbol.iterator in object); // false

// ERROR
for (const value of object) {
  console.log(value); // FAIL
}

위와 같이 배열의 경우 Symbol.iterator 메소드를 가지고 있기 때문에 순회가능하지만 object의 경우는 불가능함.

 

Iterator Protocol

Iterator는 Iterable 객체에서 반환되는 객체로 next를 호출하여 순회가능하다.

next호출시 value(값)과 done(순회 끝 여부)를 반환한다.

const array = [1, 2, 3];

// 이터러블 객체인지 확인
console.log(Symbol.iterator in array); // true

// 이터레이터 객체 할당
const it = array[Symbol.iterator]();
console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { value: undefined, done: true }

 

for..of / spread 연산자

for문, spread연산자의 경우 iterator 객체에서 done이 true가 나오기 전까지 next를 호출해 value를 반환하는 형식을 취하고있다.

const array = [1, 2, 3];
for (const value of array) {
  console.log(value);
}

console.log(...array);

Generator 함수

  • ES6에서 도입된 제너레이터(Generator) 함수는 이터러블(Iterable)을 생성하는 함수이다.
  • 제너레이터 함수는 비동기 처리에 유용하게 사용된다.

Generator함수는 일반 함수와 다르게 한번에 실행하지 않고 중지했다가 필요한 시점에 실행 할 수 있다.

// 제너레이터 함수는 일반 함수와 같이 함수의 코드 블록을 한 번에 실행하지 않고
// 함수 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재시작할 수 있는 특수한 함수
function* counter() {
  console.log('첫번째 호출');
  yield 1;                  // 첫번째 호출 시에 이 지점까지 실행된다.
  console.log('두번째 호출');
  yield 2;                  // 두번째 호출 시에 이 지점까지 실행된다.
  console.log('세번째 호출');  // 세번째 호출 시에 이 지점까지 실행된다.
}


// 함수를 실행한것이 아닌 제너레이터를 생성한것.
const counterGenerator = counter();

// Iterable Protocol 준수
console.log(Symbol.iterator in counterGenerator); // true

console.log(counterGenerator.next()); // 첫번째 호출 {value: 1, done: false}
console.log(counterGenerator.next()); // 두번째 호출 {value: 2, done: false}
console.log(counterGenerator.next()); // 세번째 호출 {value: undefined, done: true}

next() 메소드를 호출하면 처음 만나는 yield 문까지 실행되고 일시 중단된다. 또 다시 next() 메소드를 호출하면 중단된 위치에서 다시 실행이 시작하여 다음 만나는 yield 문까지 실행되고 또 다시 일시 중단된다.

next 함수 파라미터 전달

function* gen() {
  let res;
  res = yield 'start';    // 'start'

  console.log(res); // res: 1 ⟸ 두번째 next 호출 시 전달한 데이터
  res = yield res;

  console.log(res); // res: 2 ⟸ 세번째 next 호출 시 전달한 데이터
  res = yield res;

  console.log(res); // res: 3 ⟸ 네번째 next 호출 시 전달한 데이터
  return res;
}
const generatorObj = gen();

console.log(generatorObj.next());  // 제너레이터 함수 시작
console.log(generatorObj.next(1)); // 제너레이터 객체에 1 전달
console.log(generatorObj.next(2)); // 제너레이터 객체에 2 전달
console.log(generatorObj.next(3)); // 제너레이터 객체에 3 전달
/*
{ value:'start', done: false }
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: true }
*/

Generator 함수를 이용한 비동기 처리

const fetch = require('node-fetch');

// 외부 api를 사용한다.
function getUser(generatorObject, username) {
  fetch(`https://api.github.com/users/${username}`)
    .then(res => res.json())
    .then(user => {
      // user 이름을 줄테니까 다음을 실행시켜!
      generatorObject.next(user.name)
    });
}

let main;

// 비동기 함수가 포함되어있는 메인함수
function* mainFunction() {
  let user;

  // getUser를 실행하고 멈춰있어!
  user = yield getUser(main, 'jessie');
  console.log('1user - ', user);
  user = yield getUser(main, 'kevin');
  console.log('2user - ', user);
  user = yield getUser(main, 'albert');
  console.log('3user - ', user);
}

// iterator 함수 반환
main = mainFunction();
// main 함수 실행
main.next();

 

Async/Await을 이용한 비동기 처리

위와 기능은 같지만 한결 보기 편함.

const fetch = require('node-fetch');

(async function () {
  let username, res, user;

  username = 'jessie';
  res = await fetch(`https://api.github.com/users/${username}`);
  user = await res.json();
  console.log('res.name - ', user.name);

  username = 'kevin';
  res = await fetch(`https://api.github.com/users/${username}`);
  user = await res.json();
  console.log('res.name - ', user.name);

  username = 'albert';
  res = await fetch(`https://api.github.com/users/${username}`);
  user = await res.json();
  console.log('res.name - ', user.name);
})();

출처

poiemaweb.com/es6-generator

 

Generator | PoiemaWeb

ES6에서 도입된 제너레이터(Generator) 함수는 이터러블을 생성하는 함수이다. 제너레이터 함수를 사용하면 이터레이션 프로토콜을 준수해 이터러블을 생성하는 방식보다 간편하게 이터러블을 구

poiemaweb.com

poiemaweb.com/es6-iteration-for-of

 

'개발 언어 > NodeJS' 카테고리의 다른 글

Deno  (0) 2020.06.15
NodeJS - WebRTC  (0) 2020.02.28
NodeJS - Socket IO  (0) 2020.02.28
비동기 프로그래밍  (0) 2020.01.11
자바스크립트 - 프로토타입 상속  (0) 2019.12.03
댓글