데브코스 TIL -DAY9 -ES6-비동기적 동시성 함수

조주영·2021년 8월 12일
1

데브코스-TIL

목록 보기
11/34

동기(synchronous)

요청과 결과가 동시에 일어난다.
A노드와 B노드 사이의 작업 처리 단위(transaction)를 동시에 맞춘다는 것

비동기(Asynchronous)

요청과 결과가 동시에 일어나지 않는다.
노드 사이의 작업 처리 단위를 동시에 맞추지 않아도 된다.
동기보다 필요할때 사용하기에 효율적이다.

동기는 추구하는 같은 목적이 동시에 이루어지며,
비동기는 추구하는 목적이 다를 수도 있고, 동시에 이루어지지도 않는다.

callback & Promise

callback

필요할때 불러쓰는 함수

  • 비동기 상황을 일급값으로 다룬다는 것에서 callback과 차이가있다.
    비동기를 값으로 만드는 promise
  • promise라는 클래스를 통해 만들어진 인스턴스를 반환
  • 대기 성공 실패를 다루는 일급 값으로 이루어져 있다.
  • 대기와 일을 끝내는 것들을 코드나 컨테스트로만 다루는 것이 아니라 대기 되어 지는 값을 만든다 라는 것이 콜백과 큰 차이를 가지고 있다.
  • 일급이라는 얘기는 변수에할당및 일들을 이어 나갈 수 있다.
    function add10(a, callback) {
        //인자를 받고(a), 함수가 일을 마쳤을 떄 결과를 전달할(callback)
        setTimeout(() => callback(a + 10), 100); //100ms 딜레이
    }

    var a = add10(5, res => {
        add10(res, res => {
            add10(res, res => {
                log(res);
            });
        });
    });
    console.log(a);//undifind

Promise

Promise
비동기를 값으로 만드는 Promise
callback과 가장 큰 차이점

promise는 promise라는 클래스를 통해 만들어진 인스턴스를 반환하는데
대기, 성공, 실패를 다루는 일급값으로 이루어져 있다.



  function add20(a) {
      return new Promise(resolve => setTimeout(() => 
      resolve(a + 20), 100));
    }

  var b = add20(5)
      .then(add20)
      .then(add20)
      .then(log);
     //console.log(b);//promise
     //console.log(add10(5,_=>_));//undifiend
     //console.log(add20(5,_=>_));//promise

callback으로 생성된 변수a는 undefined되고,
promise로 만든 b는 리턴된다.

그래서 Promise의 경우, 어떤 함수에게 전달될 수도 있고
이벤트를 계속 이어나갈 수 있다.

값으로서의 Promise 활용

const delay100 = a => new Promise(resolve =>
        setTimeout(() => resolve(a), 100));

    const go_promise = (a, f) => a instanceof Promise ? a.then(f) : f(a);
    const add5 = a => a + 5;

    var r = go_promise(10, add5);
    log(r);

    var r2 = go_promise(delay100(10), add5);
    r2.then(log);

이는 아래의 식과 똑같은 표현이다.

    const n1 = 10;
    go_promise(go_promise(n1, add5), log);

    const n2 = delay100(10);
    go_promise(go_promise(n2, add5), log);
const n1 = 10;
log(go_promise(go_promise(n1, add5), log));

const n2 = delay100(10);
log(go_promise(go_promise(n2, add5), log));

n1은 undefined가 나오고(promise가 아님)
n2는 Promise가 나온다.

Promise를 사용하면 어떤 일을 한 결과의 상황을 일급값으로 만들어서 지속적으로 어떤 일들을 연결 해서 해결 할 수 있다.

합성 관점에서의 Promise와 모나드

f · g 또는 f(g(x))함수 합성
함수합성? f((g(x)) 를 생각하라.
안전하게 합성하기위해 모나드라는 개념이 있다.
비동기 상황을 안전하게 합성이 promise다

가령 이런 코드가 있을 때

    const g = a => a + 1;
    const f = a => a * a;

    log(f(g(1))); // 1 -> 4
    log(f(g())); // 공백 -> ?
  ...

두 번째 로그는 공백에서 에러가 뜨기 때문에 안전한 합성이라고 보기 어렵다. 안전한 인자가 들어와야 하는 함수라고 볼 수 있다.
값이 있는지 없는지 모를 때에도 안전하게 합성하려고, 모나드를 쓴다.

모나드는 박스를 가지고 있다고 한다.
함수합성을 박스[] 가 가지고 있는 특성을통해합성을 해보면,

log([1].map(g).map(f));//[4]
Array.of(1).map(g).map(f).forEach(r=>log(r));//4

map까지 존재하는 상태라면, foreach를 통해 log

[1,2,3].map(g).filter(a=>a%2).map(f).forEach(r=>log(r));
Promise.resolve(2).then(g).then(f).then(r=>log(r));

프로미스는 then으로 함수를 합성 결과는 9
프로미스는 안에 값이 있거나 없거나의 합성을 안전하게하려는게 아니다!xxxxx
프로미스는 대기가 되어있는 값 (비동기)합성을 안전하게 하려는 것

new Promise(resolve => 
   setTimeout(()=> resolve(2),100)
    ).then(g).then(f).then(r=>log(r));

맵을쓰는이유?
어레이의 정확한 정의를 모를수도 있기에 안정적으로 실행하고 ,만들어진 값을 가지고 무언가를 하기위해 사용되는 도구

결론:

프로미스는 합성관점에서 봣을떄는 비동기상황에서도 함수를 적절한 시점에 평가하는 도구로 사용

Kleisli Composition & Promise

오류가 있을 수 있는 상황에서 안전하게 함수합성하는 것

    // f . g
    // f(g(x)) = f(g(x))
    // f(g(x)) = g(x)

    var users = [
        {id: 1, name: 'aa'},
        {id: 2, name: 'bb'},
        {id: 3, name: 'cc'}
    ];

    //user를 id값으로 찾는 함수를 만들자

    const getUserById = id =>
        find(u => u.id == id, users);

    const f = ({name}) => name;
    const g = getUserById;
    const fg = id => f(g(id));

이 경우 users가 pop,push가 빈번히 이루어 진다면, 대응하기 어렵다.
ex)
두 번의 pop으로 데이터가 id: 1일 때만 남아있는데 fg(2)를 부르면 에러가 발생한다.

Promise
  var users = [
        {id: 1, name: 'aa'},
        {id: 2, name: 'bb'},
        {id: 3, name: 'cc'}
    ];
  
  const getUserById = id =>
        find(u => u.id == id, users) || Promise.reject('엄소용');
  const f = ({name}) => name;
  const g = getUserById;
  
  const fg = id => Promise.resolve(id).then(g).then(f).catch(a => a);

  fg(2).then(log);
  
  users.pop();
  users.pop();

  fg(1).then(log);
  
  setTimeout(function () {
        users.pop();
        users.pop();
        fg(2).then(log);
    }, 10);

go, pipe, reduce의 비동기 제어

go(1,
  a => a + 10,
  a => a + 1000,
  a => a + 10000,
  log);

기존에 했던 fx.js파일의 reduce를 바꿔준다


const reduce = curry((f, acc, iter) => {
    if (!iter) {
        iter = acc[Symbol.iterator]();
        acc = iter.next().value;
    } else {
        iter = iter[Symbol.iterator]();
    }
    let cur;
    while (!(cur = iter.next()).done) {
        const a = cur.value;
        acc = f(acc, a);
    }
    return acc;
});


const reduce = curry((f, acc, iter) => {
    if (!iter) {
        iter = acc[Symbol.iterator]();
        acc = iter.next().value;
    } else {
        iter = iter[Symbol.iterator]();
    }
    return go1(acc, function recur(acc) {
        let cur;
        while (!(cur = iter.next()).done) {
            const a = cur.value;
            acc = f(acc, a);
            if (acc instanceof Promise) return acc.then(recur);
        }
        return acc;
    });
});

go1 도 추가한다.

const go1 = (a, f) => a instanceof Promise ? a.then(f) : f(a);

ex)

    go(Promise.resolve(1),
        a => a + 10,
        a => Promise.resolve(a + 100),
        a => a + 1000,
        a => a + 10000,
        log).catch(a => console.log(a));




    go(Promise.resolve(1),
        a => a + 10,
        a => Promise.resolve(a + 100),
        a => Promise.reject('error !'), 
        a => console.log('----'),
        a => a + 1000,
        a => a + 10000,
        log).catch(a => console.log(a));

느낀점

오늘은 모든 내용을 담아내지 못하였다. 비동기적으로 지연성 reduce map, filter 를 promise로 구현도 해보았고, 이들을 병렬적으로도 실행시켜봤는데, 강의를 듣고있다기보다, 인동님의 코딩을 구경하는 듯 했다.
async, await개념과 함께 then으로 값을 호출해줘야 한다는 것 도 알았지만, 내가 바로바로 써먹을 수 없을것 같아서 너무 슬펐다.... 내일은 cs스터디 발표가 있고 과제를 마무리 해야한다. 과제를 2틀째 붙잡고 있는데, 답이 원하는데로 안 나와 또 슬펐다ㅠ 내일까지 해결되지 않는다면, 강사님의 세션이 끝난후 해답지를 보고 감을 다시잡고 주말에 재정비 해야겠다... 슬픈하루 마무리하면서 -끝

profile
꾸준히 성장하기

1개의 댓글

comment-user-thumbnail
2021년 8월 17일

오,, 새로 알고 가여!

답글 달기