๐ Chapter 8: ๋น๋๊ธฐ ์ด๋ฒคํธ์ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌ
๐ ๊ณจ์นซ๋ฉ์ด ๋น๋๊ธฐ ์ฝ๋โ
- ๋น์ฐจ๋จ ๋น๋๊ธฐ ํธ์ถ ์ฝ๋๋ฅผ ๊ตฌํํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋๋ฐ ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ๋ชฉ์ ์ก๋๋ค.
- ํจ์ ๊ฐ์ ์ผ์์  ์์กด ๊ด๊ณ๊ฐ ํ์ฑ
 - ์ด์ฉ ์ ์์ด ์ฝ๋ฐฑ ํผ๋ผ๋ฏธ๋ ๋ช์ ๋น ์ง
 - ๋๊ธฐ/๋น๋๊ธฐ ์ฝ๋์ ํธํ๋์ง ์๋ ์กฐํฉ
 
 
๐ ํจ์ ๊ฐ์ ์ผ์์  ์์กด ๊ด๊ณ๊ฐ ํ์ฑโ
- ์ผ์์  ๊ฒฐํฉ(temporal coupling) (์ผ์์  ์์ง temporal cohesion)์ ์ด๋ค ํจ์๋ฅผ ๋ ผ๋ฆฌ์ ์ผ๋ก ๋ฌถ์ด ์คํํ ๋ ๋ฐ์ํ๋ค.
 - ๋ฐ์ดํฐ๊ฐ ๋์ฐฉํ ๋๊น์ง, ๋๋ ๋ค๋ฅธ ํจ์๊ฐ ์คํ๋ ๋๊น์ง ์ด๋ค ํจ์๊ฐ ๊ธฐ๋ค๋ ค์ผ ํ๋ ๊ฒฝ์ฐ์ด๋ค.
 - ๋ฐ์ดํฐ๋ ์๊ฐ์ด๋ ์ด๋ ์ชฝ์ ์์งํ๋ ์๊ฐ๋ถํฐ ๋ถ์ํจ๊ณผ๊ฐ ๋ฐ์ํ๋ค.
 - ์๊ฒฉ IO ์์ ์ ๋๋จธ์ง ๋ค๋ฅธ ์ฝ๋์ ๋นํด ์๋๊ฐ ๋๋ฆด ์๋ฐ์ ์์ผ๋ฏ๋ก ๋ฐ์ดํฐ ์์ฒญ ํ ๋ค์ ๋์์ฌ ๋๊น์ง '๋๊ธฐ' ๊ฐ๋ฅํ ๋น์ฐจ๋จ ํ๋ก์ธ์ค์๊ฒ ์ฒ๋ฆฌ๋ฅผ ์์ํ๋ค.
 - ์ฝ๋ฐฑ ํจ์๋ ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋ง์ด ์ฐ์ด์ง๋ง, ๋๋ ๋ฐ์ดํฐ๋ฅผ ์์ฐจ์ ์ผ๋ก ๋ก๋ํ ๊ฒฝ์ฐ ํ์ฅํ๊ธฐ๊ฐ ์ด๋ ต๊ณ ๊ฒฐ๊ตญ ์ฝ๋ฐฑ ํผ๋ผ๋ฏธ๋์ ๋น ์ง๊ฒ ๋๋ค.
 
๐ ์ฝ๋ฐฑ ํผ๋ผ๋ฏธ๋์ ๋ช์ ๋น ์งโ
- ์ฝ๋ฐฑ์ ์ฃผ์ฉ๋๋ ์ฒ๋ฆฌ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ํ๋ก์ธ์ค๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๋์ค UI๋ฅผ ์ฐจ๋จํ์ง ์๋ ๊ฒ์ด๋ค.
 - ์ฝ๋ฐฑ์ ๋ฐ๋ ํจ์๋ ๊ฐ์ ๋ฐํํ๋ ๋์ **์ ์ด์ ์ญ์ (inversion of control)**์ ์ค์ฒํ๋ค.
 
var students = null;
getJSON('/students',
  function(students) {
    showStudents(students);
  },
  function(error) {
    console.log(error.message);
  },
);
- ๊ทธ๋ฌ๋ ์ด๋ฐ ์์ ์ ์ด์ ์ญ์  ๊ตฌ์กฐ๋ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ์ค๊ณ ์ฌ์๊ณผ ์ ๋ฉด์ผ๋ก ๋ฐฐ์น๋๋ค.
 - ํจ์ํ ํ๋ก๊ทธ๋จ์ ํจ์๋ ์๋ก ๋ ๋ฆฝ์ ์ด๋ฉฐ, ๊ฐ์ ํธ์ถ์์ ์ฆ์ ๋ฐํํด์ผ ํ๋ค.
 
๐ ์ฐ์์ฒด ์ ๋ฌ ์คํ์ผโ
- ์ค์ฒฉ๋ ์ฝ๋ฐฑ ํจ์๋ ์ฝ๊ธฐ๋ ์ด๋ ต์ง๋ง, ์๊ธฐ ์ค์ฝํ ๋ฐ ์์ ์ด ์ค์ฒฉ๋ ํจ์์ ๋ณ์ ์ค์ฝํ๋ฅผ ๊ฐ์ผ ํด๋ก์ ๋ฅผ ๋ง๋ ๋ค.
 - ์ด๋ค ํจ์๋ฅผ ๋ค๋ฅธ ํจ์์ ์ค์ฒฉํ๋ ๊ฑด, ๊ทธ ํจ์๊ฐ ์ด๋ค ์ผ์ ๋ฌ์ฑํ๊ธฐ ์ํด ์์ ์ ์ธ๋ถ ๋ณ์์ ์ง์  ์ ๊ทผํด์ผ ํ ๊ฒฝ์ฐ์๋ง ์๋ฏธ๊ฐ ์๋ค.
 - ํ์ง๋ง ๋ด๋ถ ์ฝ๋ฐฑ ํจ์๋ ๋ถํ์ํ ์ธ๋ถ ๋ฐ์ดํฐ๋ฅผ ์ฐธ์กฐํ๋ ๋ ํผ๋ฐ์ค๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
 - ์ด๋ฐ ์ฝ๋๋ฅผ ์ฐ์์ฒด ์ ๋ฌ ์คํ์ผ(continuation-passing style, CPS) ๋ก ๋ฐ๊พธ์ด ๊ฐ์ ์ด ๊ฐ๋ฅํ๋ค.
 
var selector = document.querySelector;
selector('#search-button').addEventListener('click', handleClickEvent);
const processGrades = function (grades) {
  // ํ์์ ์ ์ ๋ฆฌ์คํธ๋ฅผ ์ฒ๋ฆฌ..
};
const handleMouseMovement = () => 
  getJSON(`/students/${info.ssn}/grades`, processGrades);
const showStudent = function (info) {
  selector('#student-info').innerHTML = info;
  selector('#student-info').addEventListener(
    'mouseover', handleMouseMovement
  );
};
const handleError = error => 
  console.log('error: ' + error.message);
const handleClickEvent = function (event) {
  event.preventDefault();
  let ssn = selector('#student-info').value;
  if(!ssn) {
    alert('์๋ชป๋ ssn!');
    return;
  }
  else {
    getJSON(`/students/${ssn}`, showStudent).fail(handleError);
  }
}
- CPS๋ ๋น์ฐจ๋จ ํ๋ก๊ทธ๋จ์ ์กฐ๊ฐ๋ค์ ๊ฐ๋ณ ์ปดํฌ๋ํธ๋ก ๋ถ๋ฆฌํ๊ธฐ ์ํ ํ๋ก๊ทธ๋๋ฐ ์คํ์ผ์ด๋ค.
 - ์ฌ๊ธฐ์ ์ฝ๋ฐฑ ํจ์๋ ํ์ฌ ์ฐ์์ฒด(current continuation) ๋ผ๊ณ ๋ถ๋ฅด๋ฉฐ, ์ด ํจ์ ์์ฒด๋ฅผ ํธ์ถ์์๊ฒ ๋ฐํ๊ฐ์ผ๋ก ๋๋ ค์ค๋ค.
 - CPS์ ์ค์ํ ๊ฐ์ ์ ์ฝํ ์คํธ ์คํ์ ํจ์จ์ด ์ข๋ค๋ ์ ์ด๋ค.
 - ์ด์ด์ง๋ ๊ณผ์ ์์ ํ์ฌ ํจ์์ ์ฝํ ์คํธ๋ฅผ ์ ๋ฆฌํ๊ณ ์ ์ฝํ ์คํธ๋ฅผ ๋ง๋ค์ด ๋ค์ ํจ์๋ฅผ ์ง์ํ๋ ์์ผ๋ก ํ๋ก๊ทธ๋จ์ ํ๋ฆ์ ๊ณ์ ์ด์ด๊ฐ๋ค.
 - CPS ์ฝ๋ฉ์ ์ฝ๋์ ์์กดํ๋ ์ผ์์  ์์กด ๊ด๊ณ๋ฅผ ์ฒ๊ฒฐํ๊ณ , ๋น๋๊ธฐ ํ๋ฆ์ ์ ํ์ ์ธ ํจ์ ํ๊ฐ ํํ๋ก ๋๊ฐ์ํค๋ ๋ฅ๋ ฅ์ด ์๋ค.
 
๐ ๋น๋๊ธฐ ๋ก์ง์ ํ๋ผ๋ฏธ์ค๋ก ์ผ๊ธํโ
- ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ด๋ผ๋ฉด ์ด๋ฐ ํน์ฑ์ ์ง๋
์ผ ํ๋ค.
- ํฉ์ฑ๊ณผ ๋ฌด์ธ์ ํ๋ก๊ทธ๋๋ฐ์ ์ด์ฉํ๋ค.
 - ์ค์ฒฉ๋ ๊ตฌ์กฐ๋ฅผ ๋ณด๋ค ์ ํ์ ์ผ๋ก ํ๋ฅด๊ฒ ๋๋ ค ํธ๋ค.
 - ์ผ์์  ๊ฒฐํฉ์ ์ถ์ํ๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฐ์๋ ๋ ์ด์ ์ ๊ฒฝ ์ธ ํ์๊ฐ ์๋ค.
 - ์ฌ๋ฌ ์ฝ๋ฐฑ ๋์ , ๋จ์ผ ํจ์๋ก ์๋ฌ ์ฒ๋ฆฌ ๋ก์ง์ ํตํฉํ์ฌ ์ฝ๋ ํ๋ฆ์ ์ํ ํ๊ฒ ํ๋ค.
 
 - ๋ชจ๋๋์๋ ํ๋ผ๋ฏธ์ค(promise) ๋ผ๋ ๊ฒ์ด ์กด์ฌํ๋๋ฐ ํ๋ผ๋ฏธ์ค๋ ์ค๋ ๊ฑธ๋ฆฌ๋ ๊ณ์ฐ์ ๋ชจ๋๋๋ก ๊ฐ์ธ๋ ๊ฐ๋ ์ด๋ค.
 - ํ๋ผ๋ฏธ์ค๋ ์ค๋ ๊ฑธ๋ฆฌ๋ ๊ณ์ฐ์ด ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ ธ๋ค๊ฐ ๋ฏธ๋ฆฌ ๋งคํํ ํจ์๋ฅผ ์คํํ๋ค.
 - ํ๋ผ๋ฏธ์ค๋ ์ฐ์งํ๊ณ ํฌ๋ช ํ๊ฒ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๊ฐ๋ ์ด๋ค.
 - ํ๋ผ๋ฏธ์ค๋ ๋์ค์ ์ฒ๋ฆฌ๊ฐ ๋๋๋ ๊ฐ์ด๋ ํจ์๋ฅผ ๊ฐ์ผ๋ค.
 - ํ๋ผ๋ฏธ์ค์ ์ํ๋ ์ธ์ ๋ ๋ณด๋ฅ(pending), ์ด๋ฃธ(fulfilled), ๋ฒ๋ฆผ(rejected), ๊ท๊ฒฐ(settled) ํ๋์ด๋ค.
 - ์ฒ์์ ๋ณด๋ฅ(๋ฏธ๊ฒฐ) ์ํ๋ก ์์ํ๊ณ ์ค๋ ๊ฑธ๋ฆฌ๋ ์์ ๊ฒฐ๊ณผ์ ๋ฐ๋ผ ์ด๋ฃธ(resolve) ๋๋ ๋ฒ๋ฆผ(rejected) ์ํ๋ก ๋ถ๊ธฐํ๋ค.
 - ํ๋ผ๋ฏธ์ค๊ฐ ๋ฌธ์ ์์ด ์ด๋ฃจ์ด์ง๋ฉด ๋ค๋ฅธ ๊ฐ์ฒด์ ๋ฐ์ดํฐ๊ฐ ๋น๋ํ์์ ํต๋ณดํ๊ณ , ์ฒ๋ฆฌ ๋์ค ์๋ฌ๊ฐ ๋๋ฉด ๋ฏธ๋ฆฌ ๋ฑ๋กํ ์คํจ ์ฝ๋ฐฑ ํจ์๋ฅผ ํธ์ถํ๋ค. ์ด๋ ํ๋ผ๋ฏธ์ค๋ ๊ท๊ฒฐ๋ ์ํ๋ผ๊ณ ๋ณธ๋ค.
 
var fetchData = new Promise(function(resolve, reject) {
  // ๋น๋๊ธฐ ํน์ ์ค๋ ๊ฑธ๋ฆฌ๋ ๊ณ์ฐ์ ํ๋ค.
  if (์ฑ๊ณตํ๋ฉด) {
    resolve(result);
  }
  else {
    reject(new Error('error'));
  }
});
- ํ๋ผ๋ฏธ์ค ์์ฑ์๋ ๋น๋๊ธฐ ์์
์ ๊ฐ์ผ ํจ์(์ก์
 ํจ์)๋ฅผ ๋ฐ๊ณ  ์ด ํจ์๋ 
resolve์reject์ฝ๋ฐฑ 2๊ฐ๋ฅผ ๋ฐ๊ณ , ๊ฐ๊ฐ ํ๋ผ๋ฏธ์ค๊ฐ ์ด๋ฃธ/๋ฒ๋ฆผ ์ํ์ผ ๋ ํธ์ถ๋๋ค. 
var Scheduler = (function () {
  let delayedFn = _.bind(setTimeout, undefined, _, _);
  return {
    delay5: _.partial(delayedFn, _, 5000),
    delay10: _.partial(delayedFn, _, 10000),
    delay: _.partial(delayedFn, _, _),
  };
})();
var promiseDemo = new Promise(function(resolve, reject) {
  Scheduler.delay5(function () { // ์ค๋๊ฑธ๋ฆฌ๋ ์์
์ ์ง์ฐ ํจ์๋ก ๋ํ๋ธ๋ค.
    resolve('์๋ฃ!');
  });
});
promiseDemo.then(function(status) {
  console.log('5์ด ํ ์ํ: '+ status); // 5์ด ํ ํ๋ผ๋ฏธ์ค๊ฐ ๊ท๊ฒฐ๋๋ค.
})
๐ ๋ฏธ๋์ ๋ฉ์๋ ์ฒด์ธโ
- ํ๋ผ๋ฏธ์ค ๊ฐ์ฒด๋ 
then๋ฉ์๋๋ฅผ ์ง๋๋๋ฐ ํ๋ผ๋ฏธ์ค์ ๋ณด๊ด๋ ๋ฐํ๊ฐ์ ์ด๋ค ์ฐ์ฐ์ ์ํํ๊ณ ๋ค์ ํ๋ผ๋ฏธ์ค ํํ๋ก ๋๋๋ฆฌ๋ ๋ฉ์๋์ด๋ค. - API๋ฅผ ํ๋ผ๋ฏธ์คํํ๋ฉด ๊ธฐ์กด ์ฝ๋ฐฑ๋ณด๋ค ํจ์ฌ ์ฝ๋๋ฅผ ๋ค๋ฃจ๊ธฐ ์ฌ์์ง๋ค.
 
getJSON('/students')
  .then(hide('spinner')) // ๊ฐ์ ๋ฐํํ์ง ์๋ ํจ์๋ผ์ ํ๋ผ๋ฏธ์ค๋ก ๊ฐ์ผ ๊ฐ์ ํ์ then์ผ๋ก ๋๊ธด๋ค.
  .then(R.filter(s => s.address.country == 'US'))
  .then(R.sortBy(R.prop('ssn')))
    .then(R.map(student => {
      return getJSON('/grades?ssn='+ student.ssn)
        .then(R.compose(Math.ceil,
          fork(R.divide, R.sum, R.length))) // ํจ์ ์กฐํฉ๊ธฐ์ ๋๋ค JS ํจ์๋ก ํ๊ท ์ ๊ณ์ฐ
          .then(grade =>
            IO.of(R.merge(student,
            { 'grade': grade })) // IO ๋ชจ๋๋๋ก ํ์๊ณผ ์ ์ ๋ฐ์ดํฐ๋ฅผ DOM์ ํ์ํ๋ค.
            .map(R.props(['ssn', 'firstname', 'lastname', 'grade']))
            .map(csv)
            .map(append('#student-info')).run())
    }))
    .catch(function(error) {
      console.log('error: '+ error.message);
    });
- ๋น๋๊ธฐ ํธ์ถ์ ์ฒ๋ฆฌํ๋ ์ธ๋ถ ๋ก์ง์ ํ๋ผ๋ฏธ์ค๊ฐ ๋์ ์ฒ๋ฆฌํ๋ฏ๋ก ๋ง์น ๊ฐ ํจ์๋ฅผ ์์๋๋ก ํ๋์ฉ ์คํํ๋ฏ ํ๋ก๊ทธ๋จ์ ์์ฑํ ์ ์๋ค.
 - ์ด๋ฐ ์์ค์ ์ ์ฐ์ฑ์ ์์น ํฌ๋ช ์ฑ์ด๋ผ๊ณ ํ๋ค.
 Promise.all์ ์ด์ฉํ๋ฉด ํ ๋ฒ์ ์ฌ๋ฌ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ ค๋ฐ๋ ๋ธ๋ผ์ฐ์ ์ ๋ฅ๋ ฅ์ ๊ทน๋ํํ ์ ์๋ค.- ์ดํฐ๋ฌ๋ธ ์ธ์์ ํฌํจ๋ ๋ชจ๋ ํ๋ผ๋ฏธ์ค๊ฐ ๊ท๊ฒฐ๋๋ ์ฆ์ ๊ฒฐ๊ณผ ํ๋ผ๋ฏธ์ค๋ ๊ท๊ฒฐ๋๋ค.
 
๐ ๋๊ธฐ/๋น๋๊ธฐ ๋ก์ง์ ํฉ์ฑโ
- ์๋ ์ฝ๋์์ ์ค์ํ ๊ฑด 
student๊ฐ์ฒด๊ฐ ์กด์ฌํ๋ฉด ์ด ๊ฐ์ฒด๋ก ํ๋ผ๋ฏธ์ค๊ฐ ๊ท๊ฒฐ๋๋ฉฐ ๊ทธ ์ธ์๋ ๋ฒ๋ ค์ง๋ค๋ ์ฌ์ค์ด๋ค. 
// ๋ธ๋ผ์ฐ์ ์ IndexedDB์ฌ์ฉ
const find = function(db, ssn) {
  let trans = db.transaction(['students'], 'readonly');
  const store = trans.objectStore('students');
  return new Promise(function(resolve, reject) {
    let request = store.run(ssn);
    request.onerror = function() {
      if(reject) {
        reject(new Error('error')); // ์คํจ
      }
    };
    request.onsuccess = function() {
      resolve(request.result); // ์ฑ๊ณต
    }
  })
}
- ํ๋ผ๋ฏธ์ค๋ ์ฝ๋๋ฅผ ๊ฑฐ์ ๊ณ ์น์ง ์์๋ ๋ฏธ๋์ ํจ์ ํฉ์ฑ๊ณผ ๋๋ฑํ๊ฒ ํจ์๋ฅผ ํ๋ผ๋ฏธ์ค์ ํฉ์ฑํ ์ ์๋๋ก ๋น๋๊ธฐ ์ฝ๋์ ์คํ์ ์ถ์ํ๋ค.
 - ๋์ฐ๋ฏธ ํจ์๋ฅผ ์์ฑํ๋ค.
 
const fetchStudentDBAsync = R.curry(function(db, ssn) {
  return find(db, ssn);
});
// ์ด ํจ์๋ฅผ ํฉ์ฑ์ ํฌํจํ๊ธฐ ์ํด ์ ์ฅ์ ๊ฐ์ฒด๋ฅผ ์ปค๋ฆฌํ๋ค.
const findStudentAsync = fetchStudentDBAsync(db);
// ๋ฐ๋๋ธํ์๋ ์ฐ์ฐ์ ์ฒด์ด๋ํ  ์ ์๊ฒ ๋ง๋ ๋ค.
const then = R.curry(function (f, thenable) {
  return thenable.then(f);
});
const catchP = R.curry(function (f, promise) {
  return promise.catch(f);
});
// ์ฝ์์ ์๋ฌ ์์ค์ ๋ก๊ฑฐ๋ฅผ ๋ง๋ ๋ค.
const errorLog = _.partial(logger, 'console', 'basic', 'ShowStudentAsync', 'ERROR');
R.compose๋ก ๋ฌถ๋๋ค.
const ShowStudentAsync = R.compose(
  catchP(errorLog), // ์๋ฌ๋ ๋ชจ๋ ์ฌ๊ธฐ
  then(append('#student-info')), // then์ ๋ชจ๋๋ map๊ณผ ๊ฐ๋ค
  then(csv),
  then(R.props(['ssn', 'firstname', 'lastname'])),
  chain(findStudentAsync), // ๋๊ธฐ/๋น๋๊ธฐ ์ฝ๋๊ฐ ์  ๋ก ๋ง๋ฌผ๋ ค ๊ตด์ ๋๋ ์ง์ 
  map(checkLengthSsn),
  lift(cleanInput)
);
- ํจ์๊ฐ ๋ด๋ถ์ ์ผ๋ก ์ด๋ค ๋น๋๊ธฐ ๋ก์ง์ ๊ตฌ์ฌํ๋์ง, ์ด๋ค ์ฝ๋ฐฑ์ ์ผ๋์ง ๋ฑ์ ์ฒ ์ ํ ๋ฒ ์ผ์ ๊ฐ์ผ ์ฑ ์ ์ธ์ ์ธ ํฌ์ฆ๋ฅผ ์ทจํ๋ค.
 - ๋ฐ๋ผ์ ๋์์ ์คํ๋์ง ์์ง๋ง ๋์ค์ ํจ์ ์กฐํฉ๊ธฐ๋ก์์ ๋ณธ์์ ๋๋ฌ๋ผ ํจ์๋ฅผ ์๋ก ๋ถ์ฌ๋์ ๋ฌด์ธ์ ํ๋ก๊ทธ๋จ๋ค์ ํฉ์ฑํ์ฌ ์กฐ์ ํ ์ ์๋ค.
 
๐ ๋๊ธํ ๋ฐ์ดํฐ ์์ฑโ
- ์ ๋๋ ์ดํฐ ํจ์๋ 
function*๋ผ๊ณ ํ๊ธฐํ๋, ์ธ์ด ์์ค์์ ์ง์๋๋ ์ฅ์น์ด๋ค. - ์ด ํจ์๋ 
yield๋ฅผ ๋ง๋๋ฉด ํจ์ ๋ฐ์ผ๋ก ์ ์ ๋๊ฐ๋ค๊ฐ ์์ ์ ๋ณด๊ด๋ ์ฝํ ์คํธ๋ฅผ ์ฐพ์ ๋ค์ ๋์์จ๋ค. - ์ ๋๋ ์ดํฐ ํจ์์ ์คํ ์ฝํ ์คํธ๋ ์ ์  ์ค๋จํ๋ค๊ฐ ์ธ์ ๋ผ๋ ์ฌ๊ฐํ ์ ์์ด์ ์ ๋๋ ์ดํฐ๋ก ๋ค์ ๋์์ฌ ์ ์๋ค.
 - ์ ๋๋ ์ดํฐ๋ ํจ์๋ฅผ ํธ์ถํ๋ ์์ ์ ๋ด๋ถ์ ์ผ๋ก ์ดํฐ๋ ์ดํฐ ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ๋๊ธํจ์ ๋ถ์ฌํ๊ณ , ์ดํฐ๋ ์ดํฐ๋ ๋งค๋ฒ 
yield๋ฅผ ํธ์ถํ ๋๋ง๋ค ํธ์ถ์์๊ฒ ๋ฐ์ดํฐ๋ฅผ ๋๋ ค์ค๋ค. 
๐ ์ ๋๋ ์ดํฐ์ ์ฌ๊ทโ
- ์ ๋๋ ์ดํฐ๋ ๋ค๋ฅธ ์ ๋๋ ์ดํฐ๋ฅผ ์ผ๋ง๋ ์ง ํธ์ถํ ์ ์๋ค.
 - ์ค์ฒฉ๋ ๊ฐ์ฒด ์งํฉ์ ํํํ ๋ชจ์์ผ๋ก ๋ง๋ค๊ณ ์ถ์ ๋ ์์ฃผ ์ ์ฉํ ํน์ฑ์ด๋ค.
 - ์ ๋๋ ์ดํฐ๋ 
for..of๋ฃจํ๋ฌธ์ผ๋ก ๋ฐ๋ณตํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ์ ๋๋ ์ดํฐ์๊ฒ ์์ํ๋ ๊ฑด ๋ง์น ๋ ์ปฌ๋ ์ ์ ๋ณํฉํ ์ ์ฒด ์ปฌ๋ ์ ์ ๋ฐ๋ณตํ๋ ๊ฒ๊ณผ ๋น์ทํ๋ค. 
function* AllStudentsGenerator() {
  yield 'Church';
  yield 'Rosser';
  yield* RosserStudentGenerator(); // yield*๋ก ๋ค๋ฅธ ์ ๋๋ ์ดํฐ์๊ฒ ์์ํ๋ค.
  yield 'Turing';
  yield* TuringStudentGenerator();
  yield 'Kleene';
  yield* KleeneStudentGenerator();
}
function* RosserStudentGenerator() {
  yield 'Mendelson';
  yield 'Sacks';
}
function* TuringStudentGenerator() {
  yield 'Gandy';
  yield 'Sacks';
}
function* KleeneStudentGenerator() {
  yield 'Nelson';
  yield 'Constable';
}
for (let student of AllStudentsGenerator()) {
  console.log(student);
}
// Church
// Rosser
// Mendelson
// Sacks
// Turing
// Gandy
// Sacks
// Kleene
// NelsonA
- ์ฌ๊ท๋ก ํ์ํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
 
function* TreeTraversal(node) {
  yield node.value;
  if (node.hasChildren()) {
    for (let child of node.children) {
      yield* TreeTraversal(child); 
    }
  }
}
var root = node(new Person('Alonzo', 'Church', '111-11-1231'));
for (let person of TreeTraversal(root)) {
  console.log(person.lastname);
}
// Church
// Rosser
// Mendelson
// Sacks
// Turing
// Gandy
// Sacks
// Kleene
// NelsonA
๐ ์ดํฐ๋ ์ดํฐ ํ๋กํ ์ฝโ
- ์ ๋๋ ์ดํฐ๋ ์ดํฐ๋ ์ดํฐ ์ ๋ฐ์ ํ ๊ด๊ณ๊ฐ ์๋๋ฐ ์ฌ๋ ์๋ฃ๊ตฌ์กฐ์ฒ๋ผ ๋ฃจํ๋ก ๋ฐ๋ณต์ํฌ ์ ์๋ ๊ฒ๋ ์ดํฐ๋ ์ดํฐ ๋๋ถ์ด๋ค.
 - ์ ๋๋ ์ดํฐ ํจ์๋ ๋ด๋ถ์ ์ผ๋ก ์ดํฐ๋ ์ดํฐ ํ๋กํ ์ฝ์ ๋ฐ๋ผ 
yieldํค์๋ ๊ฐ์ ๋ฐํํ๋next()๋ฉ์๋๊ฐ ๊ตฌํ๋ Generator ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค. - Generator ๊ฐ์ฒด์ ์์ฑ์ ๋ค  ์๊ณผ ๊ฐ๋ค.
done: ์ ์ผ ๋ง์ง๋ง์ ์ดํฐ๋ ์ดํฐ๊ฐ ์ ๋ฌ๋๋ฉดtrue, ๊ทธ ์ธ์๋false๋ก ์ธํ ๋๋ค. ์ฆ,false๋ ์ดํฐ๋ ์ดํฐ๊ฐ ์์ง ๋์ค์ ๋ค๋ฅธ ๊ฐ์ ์์ฐํ ์ ์์์ ์๋ฏธํ๋ค.value: ์ดํฐ๋ ์ดํฐ๊ฐ ๋ฐํํ ๊ฐ์ด๋ค.
 - ๋ค์์ range ์ ๋๋ ์ดํฐ๋ฅผ ์์ ํํ๋ก ๊ตฌํํ ์ฝ๋์ด๋ค.
 
function range(start, end) {
  return {
    [Symbol.iterator]() {
      return this; // ๋ฐํ๋ ๊ฐ์ฒด๊ฐ ์ดํฐ๋ฌ๋ธ์์ ๋ํ๋ธ๋ค.
    },
    next() {
      if(start < end) {
        // ๋ ์์ฑํ  ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด done์ false๋ฅผ ์ธํ
        return { value: start++, done: false };
      }
      // ์์ผ๋ฉฐ done์ true๋ฅผ ์ธํ
      return { done: true, value: end };
    }
  };
}
- ์ด๋ ๊ฒ ์ ๋๋ ์ดํฐ๋ฅผ ๊ตฌํํ๋ฉด ํน์ ํ ํจํด์ด๋ ๋ช ์ธ๋ฅผ ๋ฐ๋ฅด๋ ์ด๋ค ์ข ๋ฅ์ ๋ฐ์ด ํฐ๋ผ๋ ๋ง๋ค์ด๋ผ ์ ์๋ค.
 - ๋ค์์ ์ ๊ณฑ์ ์ ๋๋ ์ดํฐ๋ฅผ ๋ง๋ ๊ฒ์ด๋ค.
 
function squares() {
  let n = 1;
  return {
    [Symbol.iterator]() {
      return this;
    },
    next() {
      return { value: n * n++ };
    }
  };
}
๐ RxJS๋ฅผ ์์ฉํ ํจ์ํ ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐโ
- RxJS๋ ํจ์ํ ํ๋ผ๋ฏธ์ค ๊ธฐ๋ฐ๊ณผ ๋น์ทํ ๋ฐฉ์์ผ๋ก ์๋ํ์ง๋ง, ๋ ๋์ ์์ค์ ์ถ์ํ๋ฅผ ์ ๊ณตํ๋ฉฐ ๋ ๊ฐ๋ ฅํ ์ฐ์ฐ์ ์ ๊ณตํ๋ค.
 
๐ ์ต์ ๋ฒ๋ธ ์์ฐจ์ด๋ก์์ ๋ฐ์ดํฐโ
- ์ต์ ๋ฒ๋ธ(observable) ์ ๊ตฌ๋ (subscribe) ๊ฐ๋ฅํ ๋ชจ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
 - ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ผ ์ฝ๊ธฐ, ์น ์๋น์ค ํธ์ถ, DB ์ฟผ๋ฆฌ, ์์คํ  ํต์ง ํธ์, ์ฌ์ฉ์ ์ ๋ ฅ ์ฒ๋ฆฌ, ์์ ์ปฌ๋ ์  ํ์, ๋จ์ ๋ฌธ์์ด ํ์ฑ ๋ฑ์ผ๋ก ๋น๋กฏ๋ ๋น๋๊ธฐ ์ด๋ฒคํธ๋ฅผ ๊ตฌ๋ ํ ์ ์๋ค.
 - ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ์ ๋ชจ๋  ๋ฐ์ดํฐ ์ ๊ณต์(data provider)์ 
Rx.Observable๊ฐ์ฒด๋ฅผ ํตํด ์ต์ ๋ฒ๋ธ ์คํธ๋ฆผ(observable stream) ์ด๋ผ๋ ๋จ์ผ ๊ฐ๋ ์ผ๋ก ์ผ์ํํ๋ค. - ์คํธ๋ฆผ์ด๋ ์๊ฐ์ ํ๋ฆ์ ๋ฐ๋ผ ๋ฐ์ํ๋ ์ด๋ฒคํธ์ ์์ฐจ์ด์ด๋ค.
 - ๊ฐ์ ์ถ์ถํ ๋ ค๋ฉด ๊ตฌ๋ ์ ํ์์ด๋ค.
 
Rx.Observable.range(1, 3)
  .subscribe(
    x => console.log(`๋ค์: ${x}`),
    err => console.log(`error: ${err}`),
    () => console.log('์๋ฃ!'),
  );
// ๋ค์: 1
// ๋ค์: 2
// ๋ค์: 3
// ์๋ฃ!
- ์ ๊ณฑ์ ์ ๋๋ ์ดํฐ ํจ์๋ฅผ ์ด์ฉํด์ ๊ฐ ์คํธ๋ฆฝ์ ์ฑ์ด๊ฒ์ด๋ค.
 
const squares = Rx.Observable.wrap(function* (n) {
  for(let i = 1; i <= n; i++) {
    return yield Observable.just(i * i);
  }
});
squares(3).subscribe(x => console.log(`๋ค์: ${x}`));
// ๋ค์: 1
// ๋ค์: 4
// ๋ค์: 9
Rx.Observable๋ก ์ด๋ค ์ต์ ๋ฒ๋ธ ๊ฐ์ฒด๋ผ๋ ๊ฐ์ธ๊ฑฐ๋ ์น๊ธํ๋ฉด ๊ด์ฐฐ๋ ๊ฐ์ ์์ดํ ํจ์๋ฅผ ๋งคํ/์ ์ฉํด์ ์ํ๋ ์ถ๋ ฅ์ ์ป๋๋ก ๋ณํํ ์ ์๋ค. ๊ฒฐ๊ตญ ๋ชจ๋๋์ด๋ค.
๐ ํจ์ํ ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐโ
Rx.Observable๊ฐ์ฒด๋ ํจ์ํ๊ณผ ๋ฆฌ์กํฐ๋ธ, ๋ ํ๋ก๊ทธ๋๋ฐ ์ธ์์ ํ๋๋ก ๋ฌถ๋๋ค.- ์ด ๊ฐ์ฒด๋ 
map,of,join๋ฑ ์ต์ํ์ ๋ชจ๋๋ ์ธํฐํ์ด์ค์ ํด๋นํ๋ ๊ตฌํ์ฒด์ ์คํธ๋ฆผ ์กฐ์์ ํนํ๋ ๋ฉ์๋๋ฅผ ์ฌ๋ฟ ๊ฑฐ๋๋ฆฐ๋ค. 
Rx.Observable.of(1, 2, 3, 4, 5)
  .filter(x => x % 2 !== 0)
  .map(x => x * x)
  .subscribe(x => console.log(`๋ค์: ${x}`));
// ๋ค์: 1
// ๋ค์: 9
// ๋ค์: 25
- ๋ค์์ SSN ํ๋ ์ ๋ ฅ๊ฐ์ด ์ฌ๋ฐ๋ฅธ์ง ๊ฒ์ฆํ๋ ์์ ์ด๋ค.
 
document.querySelector('#student-ssn')
  .addEventListener('change', function(event) {
    let value = event.target.value;
    value = value.replace(/^\s*|\-|\s*$/g, '');
    console.log(value.length !== 9 ? '๋ง์' : 'ํ๋ฆผ');
  });
// 444 ๋ง์
// 444-44-4444 ํ๋ฆผ
change์ด ๋ฒคํธ๊ฐ ๋น๋๊ธฐ๋ก ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ์ด์ฉ ์ ์์ด ์ฝ๋ฐฑ ํจ์ ํ๋์ ๋น์ง๋์ค ๋ก์ง์ ๋ชฐ์๋ฃ์๋ค. ํ์ง๋ง ๋ก์ง์ ์ถ๊ฐํ ์๋ก ์ ์  ๋ณต์กํด์ง๋ค.- ์ด๋ฒคํธ์ ํจ์ํ ๋ ์ธ๊ณ๋ฅผ ์ ๋ชฉ์ํค๊ธฐ ์ํด 
Rx.Observable๋ก ์ถ์ํ ๊ณ์ธต์ ๋๋ค. - ์ด๋ฒคํธ๋ฅผ ๊ตฌ๋ ํ๊ณ ๋น์ง๋์ค ๋ก์ง์ ๋ชจ๋ ์์ํจ์๋ก ๊ตฌํํ๋ ๊ฒ์ด๋ค.
 
Rx.Observable.fromEvent(
  document.querySelector('#student-ssn'), 'change')
  .map(x => x.target.value)
  .map(cleanInput) // SSN ๊ฐ์ ์ ์ ํ๋ค
  .map(checkLengthSsn)
  .subscribe( // Either.Right, Either.Left ์ค ์ด๋ ์ชฝ์ธ์ง ์ฒดํฌํ์ฌ ์ฌ๋ฐ๋ฅธ์ง ์ฌ๋ถ๋ฅผ ํ๋จํ๋ค.
    ssn => ssn.isRight ? console.log('Valid') : console.log('Invalid')
  );
๐ RxJS์ ํ๋ผ๋ฏธ์คโ
- RxJS๋ ๋ชจ๋ ํ๋ผ๋ฏธ์ค/A+ ํธํ ๊ฐ์ฒด๋ฅผ ์ต์ ๋ฒ๋ธ ์์ฐจ์ด๋ก ๋ณํํ ์ ์๋ค.
 - ์ฆ, ์คํ ์๊ฐ์ด ๊ธด getJSON ํจ์๋ฅผ ๊ฐ์ธ ๊ท๊ฒฐ ์์ ์ ๊ทธ ๊ฐ์ ์คํธ๋ฆผ์ผ๋ก ๋ฐ๊พผ๋ค.
 
Rx.Observable.fromPromise(getJSON('/students'))
  // ๋ชจ๋  ํ์ ๊ฐ์ฒด๋ฅผ ๋์๋ฌธ์ ๊ตฌ๋ถ ์์ด ์ด๋ฆ ์์ผ๋ก ์ ๋ ฌํ๋ค.
  .map(R.sortBy(R.compose(R.toLower, R.prop('firstname'))))
  // ํ๋์ ํ์ ๊ฐ์ฒด ๋ฐฐ์ด์ ์ต์ ๋ฒ๋ธํ ํ์ ์์ฐจ์ด๋ก ๋ฐ๊พผ๋ค.
  .flatMapLatest(student => Rx.Observable.from(student))
  // ๋ฏธ๊ตญ์ ์ด์ง ์๋ ํ์ ๊ฑฐ๋ฅด๊ธฐ
  .filter(R.pathEq(['address', 'country'], 'US'))
  .subscribe(
    student => console.log(student.fullname),
    err => console.log(err)
  );
- RxJS์ ๋ํ ์์ธํ ์ ๋ณด ์ฐธ๊ณ
 - https://xgrommx.github.io/rx-book/
 
๐ ๋ง์น๋ฉฐโ
- ํ๋ผ๋ฏธ์ค๋ ์ค๋ซ๋์ ์๋ฐ์คํฌ๋ฆฝํธ ํ๋ก๊ทธ๋๋จธ๋ค์ ๊ณจ๋จธ๋ฆฌ๋ฅผ ์์์จ, ์ฝ๋ฐฑ ์ค์ฌ์ ์ธ ์ค๊ณ๋ฅผ ํจ์ํ์ผ๋ก ํด๊ฒฐํ๋ ๋ฐฉ์์ด๋ค.
 - "๋ฏธ๋์" ํจ์๋ฅผ ํ๋ผ๋ฏธ์ค๋ก ํฉ์ฑ, ์ฒด์ด๋ํ๋ฉด ์ผ์์ ์ผ๋ก ์์กด ๊ด๊ณ๊ฐ ํ์ฑ๋ ์ฝ๋์ ์ก๋คํ ์ ์์ค ๋ก์ง์ ์ถ์ํํ ์ ์๋ค.
 - ์ ๋๋ ์ดํฐ๋ ๋น๋๊ธฐ ์ฝ๋์ ์ ๊ทผํ๋ ๋ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก, ๋๊ธํ ์ดํฐ๋ ์ดํฐ๋ก ๋ฐ์ดํฐ๋ฅผ ์ธ ์ ์๋ ์์ ์ ๋ด์ด์ค ํ๋ก๊ทธ๋๋ฐ ์ฅ์น์ด๋ค.
 - ํจ์ํ ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ์ ํ๋ก๊ทธ๋จ์ ์ถ์ํ ์์ค์ ๋์ฌ ์ด๋ฒคํธ๋ฅผ ๋ ผ๋ฆฌ์ ์ผ๋ก ๋ ๋ฆฝ๋ ๋จ์๋ก ๋ค๋ฃฐ ์ ์๊ฒ ํ๋ค.