API
API란, 어떠한 프로그램에서 제공하는 기능을 사용자가 활용할 수 있도록 만들어 둔 인터페이스이다.
API를 통해 해당 사이트, 프로그램에게 어떠한 기능을 사용하겠다 라고 전달하는 행위를
요청(Request)라고 한다. 이때 요청을 전달하는 쪽을 클라이언트(Client)라고 한다.
요청을 받아 데이터를 가공해주는 서버에게 들어온 요청을 전달해주는 것이 바로 API다.
서버로부터 클라이언트에게 들어오는 데이터를 응답(Response)이라고 한다.
HTTP(Hyper Text Transfer Protocol)
서로 다른 서버 간에 문자 형식으로 데이터를 주고 받을 때 지켜야 하는 규약이다.
HTTP에서 요청을 보낼 때는 대상 서버로 HTTP 메세지를 보내고 요청 헤더(Request header)와 요청 바디(Request body)가 그 안에 담겨진다.

HTTP Request Method
HTTP 요청은 각 요청마다 Method를 사용하며 그 역할이 모두 다르다.
- GET : 서버의 데이터를 조회하는 Method ( HTTP message에 요청 바디를 담아줄 수 없다. )
- POST : 서버에 데이터를 등록하는 Method
- PUT : 서버의 리소스를 Request body에 담긴 내용으로 수정하는 Method
- PATCH : 서버 내 리소스의 일부를 수정하는 Method
- DELETE : 서버 내 리소스를 삭제하는 Method
- OPTION : 서버에서 허용하는 Method의 목록을 알려주는 Method
상태 코드 ( Status code )
HTTP 통신을 통해 전달하는 상태 코드는 요청에 대한 응답의 결과를 세자리의 번호로 나타내줍니다.
1XX : 요청을 정상적으로 받은 것을 응답, 계속해서 작업중임을 뜻합니다.
2XX : 클라이언트의 요청을 수신, 승낙하였고, 정상적으로 요청이 수행될 것임을 의미합니다.
3XX : Redirection과 관련한 동작이 수행 되었을 때 돌려 받는 상태 코드입니다.
4XX : 클라이언트가 보낸 요청이 잘못 되었음을 의미하는 상태 코드입니다.
5XX : 서버에서 요청을 받아 로직을 수행하는 과정에서 문제가 생겼을 때 받게 되는 상태 코드입니다.
동기, 비동기
작업을 처리할 때 운영체제에서 프로세스라고 하는 작업 영역을 할당 받아 어떠한 동작을 수행한다.
코드의 실행, 프로그램의 실행, 파일 다운로드 등이 모두 프로세스별로 할당이 된다.

각 프로세스 내부에는 할당 받은 업무를 처리할 스레드가 존재한다.
스레드가 여러개라면, 하나의 프로세스 내에서 여러개의 작업을 동시에 수행할 수 있다.

다양한 작업을 동시간 대에 시작할 수 있는 스레드가 여러개 있는 작업 환경을 멀티 스레드라고 한다.

스레드가 각 프로세스별로 하나씩만 존재하는 싱글 스레드도 있다.
동기
동기란, 하나의 작업이 종료될 때까지 다음 동작을 기다리는 실행 방식이다.
비동기
비동기는 하나의 작업이 진행됨과 동시에 또 다른 작업도 함께 진행되는 것을 말한다.
JavaScript는 한번에 하나의 기능만을 수행하는 싱글 스레드이기 때문에 동기적으로 동작한다.
console.log("1")
setTimeout(() => {
console.log("2")
}, 2000)
console.log("3")
하지만 해당 코드를 실행해 보면, 1과 3이 먼저 출력되고 2초 후에 2가 출력된다.
JavaScript의 실행 환경 내부에는 call stack과 callback queue라고 하는 영역이 존재하기 때문이다.
해당 영역은 각각 자료구조 stack과 queue의 형태로 이루어져있다.
stack : LIFO(Last In First Out)으로 내부 데이터가 처리된다. 먼저 들어온 함수, 데이터가 가장 마지막에 처리되는 구조.
queue : FIFO(First In First Out)으로 내부 데이터가 처리된다. 먼저 들어온 함수, 데이터가 가장 먼저 처리되는 구조.
먼저 기본적인 함수들은 모두 call stack에 쌓이고 비동기 함수(Web APIs 포함)들은 모두 callback queue에 쌓인다.
call stack에 쌓인 기본 함수들은 먼저 담긴 함수들이 위에 쌓인 함수들의 종료를 기다리게 된다.
callback queue에 쌓인 비동기 함수들은 call stack이 비워져 있다면, 그 때 call stack으로 하나씩 옮겨진다.
setTimeout(() => {
console.log("setTimeout call")
})
const func3 = function() {
console.log("func3 call")
}
const func2 = function() {
func3()
console.log("func2 call")
}
const func1 = function() {
func2()
console.log("func1 call")
}
func1()
위와 같은 코드를 실행하면, setTimeout 함수는 지연 시간을 지정해주지 않았음에도 불구하고 비동기 함수 이므로 callback queue 영역으로 옮겨진다.

call stack 영역에 쌓인 함수는 LIFO 방식으로 수행되기 때문에 func3, func2, func1 순서로 함수가 완료된다.
그리고 해당 함수들이 모두 완료되면 그 후에 callback queue에 담긴 setTimeout 함수가 call stack으로 옮겨져
실행되며 마지막으로 "setTimeout call" 메세지가 출력된다.

비동기 처리
자바스크립트는 싱글 스레드이기 때문에 한번에 하나의 동작만 수행할 수 있습니다.
즉, 동기적으로 동작하죠.
이러한 한계점을 해결, 비동기 작업을 수행하기 위해 가장 먼저 나온 해결책은 callback 함수를 활용하는 것이었습니다.

하지만 완벽한 해결책은 아니었죠.
위와 같이 callback 함수가 여러번 중첩되는 경우
가독성에서 심각한 손해를 보게 되는 콜백 지옥(callback hell)을 만나게 되는 것이 문제였습니다.
각 함수마다 정상적인 동작에 대한 처리, 에러에 대한 처리가 필요했기 때문에 그 코드의 양은 더욱 많아질 수 밖에 없었습니다.
Promise
Promise는 현재는 얻을 수 없지만, 추후 작업이 완료되면 받아올 수 있는 데이터에 대한 접근 수단의 역할을 한다.
Promise 객체는 총 세가지의 상태를 갖는다.
대기(Pending) : 비동기 처리가 아직 완료되지 않은 상태
이행(Fulfilled) : 비동기 처리가 완료되어 결과값을 반환해준 상태
실패(Rejected) : 비동기 처리가 실패 혹은 오류가 발생한 상태
Promise 객체를 생성할 때는 내부에 함수를 인자로 넣어줄 수 있는데, 이때 그 내부 함수는 resolver, reject를 매개변수로
받아올 수 있다.
비동기 처리가 완료되면(Fulfilled), resolver가 호출되고.
비동기 처리에 실패하면(Rejected), reject가 호출된다.
then(), catch()
통신을 통해 응답을 받아오는 과정은 코드가 실행되는 과정보다 느린 경우가 많기때문에 통신 비동기 처리가 필요하다.
then()
es6 문법인 fetch()를 사용해주면 JavaScript에서 바로 통신을 수행할 수 있다.
fetch(HTTP Request).then()
fetch()를 사용한 후에 그 응답을 받아올 때까지 기다리도록 fetch()에 붙여서 then()을 사용해준다.
then() 메서드는 fetch()뿐만 아니라 Promise 객체를 돌려주는 함수라면 언제든 사용할 수 있다.
요청에 의한 통신이 완료 되었다면, then() 메서드 내부로 코드의 실행이 옮겨진다.
fetch(HTTP Request)
.then((res) => {
console.log(res)
})
then() 메서드 내부에 익명 함수를 하나 만들고 그 안에서 매개변수로 데이터를 받을 수 있는데,
이때, 받아오는 데이터가 바로 통신의 결과로 돌려준 데이터이다.
catch()
통신을 수행하다가 통신에서 문제가 생기거나 로직에서 에러가 난다면, catch 메서드로 그 분기를 나눠줄 수 있다.
fetch(HTTP Request)
.then((res) => {
console.log(res)
})
.catch((err) => {
console.error(err)
})
catch() 메서드 내부에도 익명 함수를 넣어줄 수 있는데, 해당 함수의 매개변수로 error의 내용을 받아올 수 있다.
구조분해할당 (destructuring assignment)
구조화 되어 있는 배열, 객체와 같은 데이터를 분해하여 각각의 변수에 다시 할당하는 것이다.
배열 구조분해할당
const arr = [ 1, 2, 3, 4, 5 ];
let [ one, two ] = arr; **// 배열의 구조분해할당**
console.log(one, two);
//결과
1,2
배열을 구조분해할당 해줄 때는 위의 코드처럼 작성한다.
위 처럼 작성하게되면 대괄호안의 값을 변수로 사용하고 배열을 한번 분해해서, one과 two라고 하는 새로운 변수에 담는다.
이후 one과 two 변수를 참조해 보면, 배열 arr의 가장 앞의 요소부터 차례대로 숫자 1과 2가 담겨져 있는 것을 확인할 수 있다.
객체 구조분해할당
객체를 구조분해할당 하는 방법은 조금 다르다.
const obj = {
name: "otter",
gender: "male"
}
let { name, gender } = obj
위의 코드처럼 작성해주면 객체 obj의 구조분해할당이 적용된다.
배열과 같이 선언 키워드를 먼저 적어주고, 객체는 대괄호가 아닌 중괄호를 입력해서 구조분해할당을 수행한다.
객체의 경우 실제로 obj 객체 안에 존재하고 있는 property의 key를 적어야 한다.
만약 해당 데이터를 실제로 존재하는 key가 아닌 별도의 변수명으로 관리하고 싶다면,
아래와 같이 입력하면 된다.
let { name: a, gender: b } = obj
값의 복사
스프레드 연산자 (spread operator)
스프레드 연산자는 하나로 뭉쳐져 있는 값들의 집합을 전개해주는 연산자이다.
const arr = [ 1, 2, 3, 4, 5 ];
console.log(...arr) // 1, 2, 3, 4, 5
위와 같이 입력해주면 해당 배열의 대괄호가 벗겨지게 된다.
얕은 복사 (shallow copy)
스프레드 연산자를 사용하면 값의 복사를 수행할 수 있다.
const arr = [ 1, 2, 3, 4, 5 ];
const newArr = [ ...arr ];
arr이라는 배열을 스프레드 연산자를 사용해서 펼쳐준 뒤에 다시 새로운 대괄호 안에 담아줌으로써
arr 배열이 가지고 있던 주소값과 다른 새로운 배열이 newArr이라는 변수에 담기게 된다.
객체도 스프레드 연산자를 사용한다면 복사가 가능하다.
const obj = {
name: "otter",
gender: "male"
}
const newObj = { ...obj }
위 방법은 얕은복사이므로 객체 value값에 객체가 들어있는 중첩 객체는 제대로 복사되지 않는다.
깊은 복사 (deep copy)
우리가 아는 참조 타입의 데이터는 heap이라는 임시 저장 메모리에 담기게 된다.

그리고 이 heap이라는 영역은 참조 타입 데이터와 같이 그 데이터의 크기가 유동적으로 변할 수 있다는 특징을 가진다.

스프레드 연산자를 사용해서 객체의 중괄호를 한번 벗겨냈을 때, 다른 property들은 모두 주소값의 연결이 끊어진채로 새로운 주소를 가진 데이터로 완전히 복사가 되었지만, 이때도 그 내부에 존재하는 객체는 포함되지 못했다.
이러한 문제를 해결하기위해서 JSON.stringify()와 JSON.parse()를 사용할 수 있다.
JSON.stringify()는 소괄호 안에 들어가는 값을 JSON 데이터 포맷, 즉 문자열로 변환한다.
const obj = {
name: "otter",
gender: "male",
favoriteFood: {
first: "sushi",
second: "hamburger"
}
}
const copy = JSON.stringify(obj)
console.log(copy)
// {"name":"otter","gender":"male","favoriteFood":{"first":"sushi","second":"hamburger"}}
위의 예시처럼 문자열로 변환이 된다면, copy에 담긴 값은 더이상 객체가 아니며
완전히 새로운 문자열이기 때문에 전혀 새로운 주소값을 가진다.
const deepCopy = JSON.parse(copy)
console.log(deepCopy)
/*
{
name: "otter",
gender: "male",
favoriteFood: {
first: "sushi",
second: "hamburger"
}
}
*/
이후, JSON.parse()를 사용해서 JSON 데이터 포맷을 다시 객체 형태로 바꿔주면,
이때 새로운 객체가 생성되며 deepCopy에 담기는 것이기 때문에 원본 객체와는 전혀 다른 주소값을 가진 객체가 생성된다.
rest parameter
rest parmeter는 함수의 매개변수(parameter)를 배열로 전달 받는 방식이다.
const foo = function(one, two, ...rest) {
console.log(rest)
}
foo(1, 2, 3, 4, 5) // [ 3, 4, 5 ]
매개변수를 정의하는 과정에서 rest parameter를 적용 시키면,
one과 two 매개변수에는 주어진 전달인자의 첫번째, 두번째 데이터가 담깁니다.
rest 매개변수에는 앞선 두개의 데이터를 제외한 나머지 데이터가 배열의 형태로 담기게 된다.
또한 rest parameter도 매개변수임은 다르지 않기에 원하는 이름으로 사용할 수 있다.
const foo = function(one, two, ...arr) {
console.log(arr)
// rest 파라미터 또한, 매개변수이기 때문에 임의의 변수명 지정 가능
}
foo(1, 2, 3, 4, 5) // [ 3, 4, 5 ]
const foo = function(...rest) {
console.log(rest)
}
foo(1, 2, 3, 4, 5) // [ 1, 2, 3, 4, 5 ]
전달인자로 몇개의 데이터가 들어오든 우리는 rest란 이름의 배열로 모두 받아올 수 있다.
rest parameter 주의사항
rest parameter를 작성할 때는 반드시 마지막에 위치해야 한다
'Code.camp > Precamp' 카테고리의 다른 글
| 베이스캠프 14일차 (0) | 2022.10.24 |
|---|---|
| 베이스캠프 13일차 (0) | 2022.10.22 |
| 베이스캠프 12일차 (0) | 2022.10.22 |
| 베이스캠프 11일차 (0) | 2022.10.20 |
| 베이스캠프 10일차 (0) | 2022.10.19 |