[TIL] 언더바 과제 회고, 비동기

ㅜㅜ·2022년 9월 24일
0

Today I learn

목록 보기
22/77
post-thumbnail

언더바 과제

언더바 과제는 객체와 배열을 다루는 Underbar라는 라이브러리를 직접 구현하면서 자바스크립트 내장 매서가 어떻게 콜백 함수를 활용하는지 원리를 알아보는 과제였다.

🤔 내 목표

과제의 Bare Minimum을 완료하는 것이었다. advanced, nightmare는 시간내에 어려울 거라고 이야기 하셨기 때문에 욕심 부리지 않고, 기본적인 내용이라도 완료하고자 노력했다.

🫠 결과

  • reduce를 구현하는 것만 빼면 모든 베어 미니멈 과제를 완료했으나...
    실시간 세션으로 강사님이 코드를 작성하시는 걸 보니 과연 내가 완료했던 몇몇 코드들은 제대로 작성한 게 맞는가 의문이 들었다...

  • 내가 잘못 작성했다고 느꼈던 부분은 filter, reject,map 함수였는데...
    reduce를 작성할 때 헤맸던 부분도 내가 잘못 작성한 것과 관련이 있었다.

  • each로 순회되는 배열의 요소뿐만 아니라, 배열의 인덱스, 배열자체도 받을 수 있도록 해줘야한다는 점을 간과했기 때문이다.

  • reduce에서는 iteratee에 누적값, 요소, 인덱스, 배열을 모두 매개 변수로 주어야했으나, 이전에 요소 이외에 다른 매개 변수를 고려한 적이 없었기 때문에 쉽게 코드를 작성하기 어려웠다.

  • 실제로 라이브러리로 사용될 때, 하나의 함수로 사용될 때 일어날 수 있는 모든 경우를 고려해서 설계를 해야 한다는 점이 중요하다는 걸 깨달았다.

  • if문을 작성할 때, 조건문 뒤에 오는 실행문이 한 줄인 경우 중괄호를 생략하고도 쓸 수 있다. (강사님이 쓰시는 if문은 내 거랑 다르게 왜 그렇게 짧고 간결한지...^^...)

  • 화살표 함수에서 아예 괄호들을 다 생략하고 적는 걸 실제로 보게 되니 좀 '???'하게 되었던 것 같다. 그렇게 쓸 수도 있다는 것 기억해둬야지.





비동기

  • blocking : 하나의 작업이 끝날 때까지 이어지는 작업을 ‘막는 것’

  • 동기적(synchronous) : 새로운 작업 시작 시점과 이전 작업 완료 시점이 같은 상황.
    (ex : 카페에서 주문1이 들어가고 난 뒤 주문1이 완료될 때까지 주문2를 받지 않는 상황...)

  • 비동기 처리 : 특정 코드의 연산이 끝날 때까지 코드 실행을 멈추지 않고, 다음 코드를 먼저 실행하는 방식.

  • node.js 개발자는 node.js를 non-blocking하고, 비동기(asynchronous)로 작동하는 런타임으로 개발함.

  • Js에서 특히 비동기적 실행이라는 개념이 유용한데, 아래와 같은 작업들이 비동기적으로 작동될 때 효율적이기 때문.

    • 백그라운드 실행, 로딩 등의 작업
    • 인터넷에서 서버로 요청을 보내고, 응답을 기다리는 작업
    • 큰 용량의 파일을 로딩하는 작업

비동기 사례


DOM Element의 이벤트 핸들러

:자바스크립트는 이벤트 루프를 통해 비동기식으로 처리하여 동시성을 가질 수 있다. (작업들이 동시에 처리되는 것처럼 보임) 이벤트 루프는 프로그램에서 발생하는 이벤트나 메시지를 콜백 이벤트 큐에 저장해뒀다가 하나씩 꺼내서 동작시키는 루프. (참고)

  • 마우스, 키보드 입력 (click, keydown 등)
  • 페이지 로딩 (DOMContentLoaded 등)
    (ex: DOMContentLoaded는 돔트리가 다 만들어진 뒤 돔에 접근할 수 있도록 하기 때문에 돔 생성 전에 돔을 조작하는 js 코드 실행으로 원하지 않는 결과를 내는 것을 막을 수 있음.)

타이머

  • 타이머 API (setTimeout,clearTimeout,setInterval,clearInterval)
    : setTimeout은 Web API의 한 종류로 코드를 바로 실행하지 않고, 지정한 시간만큼 기다렸다가 로직을 실행함.
  • 애니메이션 API (requestAnimationFrame)
	// 타이머 API setTimeout 예시 
	console.log('i am')
	setTimeout(function(){
      console.log('smart');
    }, 3000);
	console.log('so');
	//비동기적으로 실행 되기 때문에 setTimeout이 실행될 때까지 기다리지 않고 다음으로 넘어간다
	// 그래서 'i am' 'so' 'smart'순으로 실행된다.

서버에 자원 요청 및 응답

  • fetch API
    : 특정 URL로부터 정보를 받아오는 역할을 하고, 이 과정이 비동기로 이루어짐.
  • AJAX (XHR)
    : 제이쿼리 ajax 통신으로 실제 웹 서비스를 개발할 때 화면에 표시할 이미지, 데이터를 서버에서 불러와 표시한다.




비동기의 문제점 해결하는 방법

  • 비동기 처리는 특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 수행하기 때문에 클라이언트가 서버에 데이터를 요청했을 때 그 데이터가 도착하기도 전에 화면에 출력하는 코드가 실행되어 화면에 데이터가 출력되지 않는 문제가 생긴다.
let userInfo = {};

setTimeout(()=>{
  userInfo.data = {
    Id: 'lulu',
    name: '하니',
    IQ: 200,
    Favorite_game:"league of legend"
  }
},500);

console.log(userInfo.data.Id)
//console.log가 실행되는 시점에 아직 userInfork 빈 객체이기 때문에 id값이 undefined가 됨. 
//콜백 함수를 사용해 고쳐보면 아래와 같다.

let userInfo = {};

function printUserInfo(callback){
  setTimeout(()=>{
    userInfo.data = {
      Id:"lulu",
      name: "하니",
      IQ:200,
      Favorite_game: "league of legend"
    }
    callback()
  },500);
}

printUserInfo(()=>{console.log(userInfo.data.Id)})//lulu가 출력됨. 
  • 순서를 제어하고 싶을 때 아래와 같은 방법을 사용할 수 있다.

콜백 함수

const printStr = (string, callback) => {
  	setTimeout(
      () => {
        console.log(string)
        callback()
      },
      Math.floor(Math.random() * 100) + 1
      )
}

const printAll = () => {
  printStr("A", () => {
    printStr("B", () => {
      printStr("c", () => {})
    })
  })
}

printAll() // A,B,C 순서로 순서가 제어되며 프린트 된다! 

  • 콜백 함수의 문제점 : Callback Hell

    콜백 함수를 연속해서 사용하면 코드를 관리하고, 읽는 것이 어려워진다.

Promise

  • 콜백 지옥을 해결하기 위해 프로미스를 사용할 수 있다.
const printStr = (string) => {
  return new Promise((resolve, reject) => { // resolve, reject는 콜백 함수 
    setTimeout(
      () => {
        console.log(string)
        resolve()
      },
      Math.floor(Math.random() * 100) + 1
      )
  })
}

const printAll = () => {
  printStr("A")
  .then(()=> {
    return printStr("B")
  })
  .then(() => {
    return printStr("C")
  })
}
printAll()
  • 에러를 넘겨주는 함수가 있을 때는 프로미스 체인의 마지막에 .catch를 통해 에러 핸들링을 할 수 있다.
  • 리턴 처리를 잘 해주지 않았을 때는 아래와 같이 프로미스 지옥이 존재할 수 있다.
function gotoschool(){
  return new Promise((resolve, reject) => {
    setTimeout (()=>{resolve('1. go to school')}, 100)
  })
}
function sitandstudy(){
  return new Promise((resolve, reject) => {
    setTimeout (()=>{resolve('2. sit and study')}, 100)
  })
}
function eatLunch(){
  return new Promise((resolve, reject) => {
    setTimeout (()=>{resolve('3. eat lunch')}, 100)
  })
}
function gotoBed(){
  return new Promise((resolve, reject) => {
    setTimeout (()=>{resolve('4. go to bed')}, 100)
  })
}

gotoschool()
.then(date => {
  console.log(data)
  
  sitandstudy()
  .then(data => {
    console.log(data)
    
    eatLunch()
    .then(data => {
      console.log(data)
      
      gotoBed()
      .then(data => {
        console.log(data)
      })
    })
    
  })
  
})
  • 프로미스 체이닝으로 고치기
gotoschool()
.then(date => {
	console.log(data)
  	return sitandstudy()
})  
.then(data => {
    console.log(data)
  	return eatLunch()
})
.then(data => {
	console.log(data)
	return gotoBed()
})
.then(data => {
	console.log(data)
})

async await

  • 프로미스인데 실제로 보여지는 모습이 다른 것. 동기적인 것 같은 모습을 가짐으로써 코드 가독성을 높여줄 수 있는 방법.
  • async 함수와 await를 통해 비동기들을 동기적 프로그램처럼 사용할 수 있다.
function gotoschool(){
  return new Promise((resolve, reject) => {
    setTimeout (()=>{resolve('1. go to school')}, 500)
  })
}
function sitandstudy(){
  return new Promise((resolve, reject) => {
    setTimeout (()=>{resolve('2. sit and study')}, 500)
  })
}
function eatLunch(){
  return new Promise((resolve, reject) => {
    setTimeout (()=>{resolve('3. eat lunch')}, 300)
  })
}
function gotoBed(){
  return new Promise((resolve, reject) => {
    setTimeout (()=>{resolve('4. go to bed')}, 200)
  })
}

const result = async () => {
  const one = await gotoschool();
  console.log(one)
  
  const two = await sitandstudy();
  console.log(two)
  
  const three = await eatLunch();
  console.log(three)
  
  const four = await gotoBed();
  console.log(four)
}

result();
profile
다시 일어나는 중

0개의 댓글