코드스테이츠_S2U3_5,6W_금,월,화

윤뿔소·2022년 9월 23일
0

CodeStates

목록 보기
19/47

고차함수를 페어 프로그래밍으로 복습함!

  • 고차함수 : 전달인자로 함수를 줄 수 있고, 다른 함수를 리턴할 수도 있음.
    • 콜백 : 함수의 전달인자에 함수를 넘겨주는데 그 함수를 콜백
    • 커링 : 함수가 함수를 리턴하는 구조

Underbar

  • 거의 대부 = UnderScore, lodash가 모티브로 된 라이브러리임
  • 이 라이브러리로 고차함수의 활용을 해보자
    • 자바스크립트 배열 내장 메서드(forEach, map, filter, reduce 등)의 원리를 이해한다.
    • 콜백 함수 전달을 자유롭게 할 수 있다.
  • 비동기(콜백) 연습 하기 위해서 공부
  • 알고리즘에서 많이 쓰는 filter, reduce, map등등의 작동 원리를 보기 위해

_.each

  • _.each는 들어온 Collection에 반복적인 작업을 수행토록 만든다.
    1. collection(배열 혹은 객체)과 함수 iteratee(반복되는 작업)를 인자로 전달받아 (iteratee는 함수의 인자로 전달되는 함수이므로 callback 함수)
    2. collection의 데이터(element 또는 property)를 순회하면서
    3. iteratee에 각 데이터를 인자로 전달하여 실행. = 각 요소에 실행
  • forEach()랑 비슷, 반복하게 만드는 순회 함수(iterator)를 만들라는 얘기임
  • Collection은 객체, 배열만 받는다고 전제했으니 나눠서 해야함
    1. 배열 arr을 입력받을 경우, iteratee(ele, idx, arr)
    2. 객체 obj를 입력받을 경우, iteratee(val, key, obj)
_.each = function (collection, iteratee) {
  // iterator는 반복하는 애, iteratee 반복 당하는 함수 - 콜백!!
  if (Array.isArray(collection)) {
    for (let i = 0; i < collection.length; i++) { // 인덱스 순회
      iteratee(collection[i], i, collection);
    }
  } else {
    for (let i in collection) { // 키값 순회
      iteratee(collection[i], i, collection);
    }
  }
};
  • 핵심 : iteratee를 Collection의 각 요소에 잘 적용시킨 반복문이다. 리턴값도 없음!

_.filter

  • .filter()를 만들 차례, 만족된 요소만 '리턴'해야한다.
    1. test(element)의 결과(return 값)가 truthy일 경우, 통과
    2. test 함수는 각 요소에 반복 적용
_.filter = function (arr, test) {
  let newArr = [];
  _.each(arr, (item) => {
    if (test(item)) {
      newArr.push(item);
    }
  });
  return newArr;
};
  • 핵심
    1. 새로운 배열을 리턴해야하니 빈배열 선언 및 할당, 리턴
    2. 각 요소에 적용토록 고차 함수 설정
    3. 콜백으로 만족이 되면 / 배열에 담아주기 - test(item)

_.reduce

  • 제일 어려웠음
    1. 배열을 순회하며 각 요소에 iteratee 함수를 적용하고,
    2. 그 결과값을 계속해서 누적(accumulate)
    3. 최종적으로 누적된 결과값을 리턴
  • 전제1 : 파라미터로 iteratee 함수가 들어가는데 그 함수 안에 요소가 (acc, ele, idx, arr)로 들어감,
  • 전제2 : 누적값을 선언해놨지만 어디서부터 누적이 시작되는가에 대한 답이 없어 파라미터로 initVal이라는 시작 값을 따로 지정
  • 전제3 : iteratee 함수에 이제 acc라는 누적값도 파라미터로 들어가게끔 입력됨
_.reduce = function (arr, iteratee, initVal) {
  // 초깃값이 포인트: initVal, 총량: acc, 이전값 : pre
  // initVal이 있다면? initVal === acc, initVal이 없다면? acc === arr[0]
  let acc = initVal;
  _.each(arr, (item, idx, collection) => {
    // if (acc === undefined) { // acc를 기준으로 undefined를 해줘 1번째 반복 때 acc가 지정되면 if가 안먹이게 분기를 나눴다! 미쳤다! 더 효율적임
    if (initVal === undefined && idx === 0) {
      acc = item;
    } else {
      acc = iteratee(acc, item, idx, collection)
    }
  });
  return acc;
};
  • 핵심
  1. 누적값 설정 : 초깃값을 누적값에 옮기기, 리턴
  2. _.each로 적용, 누적값이 있는 지 없는 지 분기를 나눠 acc재할당
    • 존재x : 1번째 요소를 지금 누적값으로 설정 - 조건이 포인트!!
    • 존재o : _.eachiteratee 함수를 써줘 각 요소에 적용 - 누적값(acc)과 수행되지않은 현재 요소(item, ele, pre), 인덱스, collection을 써줌

JS는 기본적으로 동기 처리함, 하지만 브라우저에서 효율적으로 처리하기 위해 비동기 처리로 코드를 짤 때가 있음, 하는 법을 배워보자.

비동기

비교 : 카페, 식당, 치킨집, 전화와 문자 등등, 특히 에 대한 비유가 있다. 진짜 재밌음 ㅋㅋㅋ

  • 내가 식당을 갔는데 식당 특성 상, 직전에 온 사람의 주문과 제공까지 나의 주문을 받지 못한다.(blocking) 직전 사람이 주문한 음식을 받고 나서야 나의 주문을 받는다.
    • 즉! 완료 시점과 시작 시점이 같은 걸(Synchronous) '동기적이다'이라고 표현함
    • 비효율적이제?
  • 효율적으로 식당을 바꿔보자
    • 주문을 언제든지 받을 수 있고(non-blocking), 주문이 완성되는 즉시 음식 제공, 즉 완료 시점과 시작 시점이 다르다!(Asynchronous) - '비동기적'
    • 즉, 병렬처리가 더 효율적임! 완료되지 않아도 다른 행위를 할 수 있음+ 유튜브에서 비디오 재생되고 있지만, 다른 컴포넌트를 조작(메인, 댓글) 가능

비동기 속 콜백(동기)

비동기가 좋다는 건 알았지만 비동기 안에서도 동기적으로(순차적으로) 순서를 제어할 경우가 있을 수도 있다. 이 때 콜백으로 제어한다.

const printString = (str) => {
  setTimeout(() => {
    console.log(str);
  }, Math.floor(Math.random() * 100) + 1);
};
const printAll = () => {
  printString("A");
  printString("B");
  printString("C");
};
printAll(); // ABC, BCA, CAB ... 뒤죽박죽임

A, B, C를 랜덤 시간에 따라찍어내고 싶은 코드 - setTimeout으로 비동기 처리
하지만 시간에 따라 순차적이 아닌 ABC가 랜덤한 순서로 나온다.

여기서 비동기 안 동기 처리를 해 시간을 따라 나오면서 순차적으로 나오게 만들 수 있다!

const printStr = (str, callback) => {
  setTimeout(() => {
    console.log(str);
    callback(); // 추가
  }, Math.floor(Math.random() * 100) + 1);
};
const printAllCallback = () => {
  // 콜백 중첩으로 순차적 처리
  printString("A", () => { 
    printString("B", () => {
      printString("C", () => {});
    });
  });
};
printAllCallback(); // ABC가 순차적으로 랜덤한 시간에 결과가 나옴

콜백을 써줘 동기적으로 처리해 ABC를 안정적으로 도출
근데! 저게 많아지면 '콜백 지옥'이 생김(가독성 꽝, 에러 콜백마다 써줘야함), promise로 해결하자!

비동기 속 콜백의 활용 : error 처리

  • 위 코드에서는 callback()에 파라미터가 없었지만 의도적으로 없는 값 null을 넣어 조건에 따라 활용할 수 있다.
const somethingGonnaHappen = callback => {
  waitingUntilSomethingHappens();
  if (isSomethingGood) {
    callback(null, something); // 실무적으로도 대부분 에러가 앞, 데이터가 뒤로 써줌
  }
  if (isSomethingBad) {
    callback(something, null);
  }
}

somethingGonnaHappen((err, data) => {
  if (err) {
    console.log('ERROR!!');
    return;
  }
  return data;
});
  • 비동기 속 함수 대표 주자들

Promise

How to deal with 'Callback Chain and Hell'
즉! 콜백을 어떻게 다룰 것이냐에 대한 문법이다!

  • new Promise() : 생성자로 만듦
  • resolve() : go to 'Next Action'
  • reject() : 'Handle Error'
  • .then() : Promise 함수를 받을 수 있는(thenable) 것을 받아서 괄호안 콜백을 적용 뒤 리턴
    • 모든 promise는 thenable하지만 thenable은 promise만 있는 건 아님
    • then이 파라미터를 받아 콜백 함수에 적어주면 그 전 promise리턴값에 함수가 적용된 값이 리턴된다!!
  • 생성해보자 : new로 만들고, 파라미터로 넣어주고, 체이닝(.then)을 통해 설정
// Promise Constructor(생성자 함수)
const printString = (string) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(string);
      resolve(); // 실행되는 printAll()만 있기에 reject는 따로 없음
    }, Math.floor(Math.random() * 100) + 1);
  });
};
// Promise Chaining
const printAll = () => {
  printString("A")
    .then(() => {
      return printString("B");
    })
    .then(() => {
      return printString("C");
    });
};
printAll(); // A, B, C
  • Promise의 의의(위 콜백지옥 코드와 비교)
    • .then()으로 평평한 구조를 가져 가독성도 좋고 쓰기도 좋다.
    • .catch()로 콜백에 에러가 생길 때 한번만 작성해도 처리 가능!
    • .thenreturn에 다른 promise를 줘 그 promise의 resolve()를 이어받아 .then 쓸 수 있음
    • 코드가 안좋아 404 같은 4~, 5~ 오류가 나오면 .catch()를 통해 1. 앱을 죽이지(강제종료) 않고 2. 오류 화면을 띄울 수 있음

Await, Async

  • ES8부터 추가된 문법이며 Promise와 동일한 기능을 한다.
  • 비동기 코드를 await만으로 동기적으로 처리 가능하다!
  • new promise가 없어도 동기적 처리가 가능하게 만들어준다.
  • new promiseasync() => {await ~}는 같이 쓸 수 있다. .then()대신 await 사용 가능
  • async().then과도 쓰고 단독으로 쓰일 수 있지만 await는 무조건 async()에 써줘야한다.
async function showAvatar() {
  // JSON 읽기
  let response = await fetch('/article/promise-chaining/user.json');
  let user = await response.json();

  // github 사용자 정보 읽기
  let githubResponse = await fetch(`https://api.github.com/users/${user.name}`);
  let githubUser = await githubResponse.json();

  // 아바타 보여주기
  let img = document.createElement('img');
  img.src = githubUser.avatar_url;
  img.className = "promise-avatar-example";
  document.body.append(img);

  // 3초 대기
  await new Promise((resolve, reject) => setTimeout(resolve, 3000));

  img.remove();

  return githubUser;
}

showAvatar();
  • 이렇게 async()를 함수에 선언해 단독으로 promise 상태를 만듦
  • .then()보다 쓰기 쉽고 직관적
  • .then(), .catch()같이 try{await~}...catch (err) {~err}로 오류도 잡을 수 있음
  • 그런데 문법상 최대 바깥 스코프에서 .then, .catch를 써야하기에 기본 구조도 알고 있기

비동기와 API

API(Application Programming Interface) : 프로그램(앱)과 OS가 상호작용에 사용되는 언어 및 메세지의 정의와 형식 + 걍 추상화 잘된, 나와 프로그램이 상호작용되도록 도와주는 자료형 데이터
효율적으로 쓰기 위해 비동기 처리를 하며 많이 쓰이는 API가 있는데, 그것들을 알아보겠다.

타이머 API

setTimeout(실행콜백, 지연시간(밀리초)), clearTimeout(setTimerout 함수 이름)

const timer = setTimeout(function () {
  console.log('10초 후 실행');
}, 10000); 
clearTimeout(timer);
// setTimeout이 종료됨.

setInterval(실행콜백, 지연시간(밀리초), clearInterval(setTimerout 함수 이름)

const timer = setInterval(function () {
  console.log('1초마다 실행');
}, 1000);
clearInterval(timer);
// setInterval이 종료됨.

타이머 API 페어 과제

node.js 모듈 설명 및 페어 과제

  • 모듈 불러오기 2가지 방법
    1. require - exports : ES 전 버전 사용 가능, 파일 어느 지점에서든 호출 가능
    2. import - export : ES6 이후 사용가능, 무조건 맨위 호출, 사용자가 필요한 모듈만 호출 선택 가능, 성능 우수, 메모리 절약, 요즘 많이
  • {}를 붙여 디스트럭쳐링 가능! 알자!
// require
const name = require('./module.js');
module.exports = name;
const fs = require('fs');

// import
import name from './module.js';
export default name; // default 내보내기
import fs from 'fs'; // 내장
import { readFile } from 'node:fs'; // 디스트럭쳐링

Promise와 활용 복습함

궁금증

node.js fs.readFile 함수가 콜백에서 err를 어떻게 잡느냐가 궁금했다
근데 코치님이 알려주셨다.
readFile의 함수가 끝나면 그 에러인 상황을 판별(파일x 같은)해주는 기준들이 메소드에 내장되어있기 때문에 err이든 error든 어떤 이름이든 파라미터로 정해두고 그 에러만 담아주면 된다.

fetch API

서버와 연동시키는, 네트워크 요청이 가능하게 만들어주는 API
비동기 요청의 가장 큰 예

  • 기본 모양
fetch(url)
  // .json으로 파싱하기
  .then((response) => response.json())
  .then((json) => console.log(json))
  // catch로 오류 처리
  .catch((error) => console.log(error));

궁금증

  • .json과 JSON.parse의 차이가 뭐임??
    • .json은 네트워크로 가져온 내용의 body 부분을 추출
    • JSON.parse는 JSON의 문자열을 자바스크립트가 읽을 수 있게 추출

Axios

fetch를 더 편하게 만들어 줄 수 있는 서드파티 라이브러리다.
.json도 안해줘도 된다!

참고: fetch vs axios

회고

  • 진짜 어렵다. 그 자체를 이해하기엔 아직 무리다.
    하지만 그 패턴을 이해하고 활용한다면 괜찮을 것이다. 포기하지 말자

  • 코스 졸업 선배가 와서 발표를 했는데 알게 된 것, 유념할 것을 필기 하겠다.

    • 깃을 무조건 마스터, 특히 merge와 push할 때 진짜 유념해서 하자. push해버리면 돌이킬 수가 없어서 알아서든 사수분께 물어보든 꼭꼭 확인 또 확인해서 push하자.
    • 블로깅
      1. 지금은 막 쓰지만 남들도 보기 쉬운 내용을 통해 나만의 언어, 기록으로 써보기, 그래야 나도 기억 잘된다!
      2. 내가 직접 짠 코드들을 올리자! 물론 내가 짠 코드들을 올리긴 하지만 활용할 수 있는 방향으로 블로깅하자!
      3. 내가 자주 깜박하는 항목을 따로 메모해 나중에 블로깅
    • 클론코딩을 하더라도 기억에 남는 것들은 블로깅, 복습하자
profile
코뿔소처럼 저돌적으로

0개의 댓글