node.js는 chrome V8 엔진으로 빌드된 자바스크립트 런타임(개발환경)이다. 싱글쓰레드, 논블로킹, 이벤트기반 비동기 방식으로 싱글쓰레드임에도 높은 처리성능을 가지고 있다. 콜백 큐, 다양한 API를 가지고 있음.
장점 - 내장 HTTP 서버 라이브러리 포함 | JS로 프론트엔드 백엔드 모두 구현가능 | npm으로 다양한 패키지 제공
단점 - 비동기 기반의 처리방식으로 콜백지옥 | 코드 실행 후 에러 확인가능 | 세션공유시 redis와 같은 부가인프라 필요 | 싱글쓰레드 기반으로 CPU 집약적 작업에 리스크
콜백지옥 어떻게 처리?
Promise 활용 - promise의 then메서드를 이용하여 비동기 처리
asyncFunction1(arg1)
.then(result1 => asyncFunction2(result1))
.then(result2 => asyncFunction3(result2))
.then(result3 => {
// ...
})
.catch(error => {
// 오류 처리
});
Async/Await 활용 - 함수에 async 변수에 await를 사용하여 비동기 처리
async function fetchData() {
try {
const result1 = await asyncFunction1(arg1);
const result2 = await asyncFunction2(result1);
const result3 = await asyncFunction3(result2);
// ...
} catch (error) {
// 오류 처리
}
}
fetchData();
모듈화
라이브러리 사용
동기 - 순차적으로 실행 실행되며 선행작업 종료 후 다음 작업 시작 | 직관적 쉬운 디버깅 | 작업시작이 오래걸릴경우 전체프로그램이 다운 될 수 있음
비동기 - 순차적 X 선행작업 유무에 상관없이 다음 작업 진행 | 복잡한 코드 , 콜백지옥
동기보다 비동기 -> 간단한작업, 순차작업시, 단일 스레드환경, 간단한 오류처리, 코드의 가독성
이벤트루프 - 작업을 옮기는 역할
콜 스택(LIFO)에 들어온 비동기 함수를 WebAPI로 옮기고 작업이 완료되면 큐(FIFO)에 적재한 뒤 콜스택이 비워지면 자바스크립트 엔진으로 옮겨 작업을 수행하게 한다.
const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"), 500);
const baz = () => console.log("Third");
bar();
foo();
baz();
호이스팅은 JavaScript에서 변수 및 함수 선언이 코드의 최상단으로 끌어올려지는 동작
변수 호이스팅
함수 스코프 var와 블록스코프 let const
함수 호이스팅
함수 선언문 전체가 끌어올려지므로 함수 선언전에 호출 가능
함수표현식과 화살표함수는 변수가 초기화되지 않았기때문에 undefined 에러 출력
객체지향 프로그래밍이란? - 데이터를 추상화시켜 상태와 행위를 가진 객체를 만들고 객체들 간의 상호작용을 통해 로직을 구성하는 프로그래밍 방법
단일 책임 원칙 - 한 클래스는 하나의 책임만 가진다.
개방 폐쇄 원칙 - 확장에는 열려있고 변경에는 닫혀있어야한다.
리스코프 치환 원칙 - 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야한다.
인터페이스 분리 원칙 - 특정 클라이언트를 위한 인터페이스 여러개가 범용 인터페이스 하나보다 낫다.
의존관계 역전 원칙 - 추상화에 의존한다. 구체화에 의존하면 안된다.
정규화된 데이터모델 사용
데이터를 테이블 형식으로 관리하는 데이터베이스 시스템
데이터는 여러 테이블에 분리되며, 각 테이블은 행과 열로 이루어진 관계형 데이터 모델
트랜잭션 지원
ACID 특성(원자성, 일관성, 고립성, 지속성)을 보장하여 데이터의 무결성과 안전성을 제공
ACID란?
원자성 - 모두 성공하거나 하나라도 실패시 모두 실패
일관성 - 트랜잭션 실행 전 후 DB가 일관된 상태
고립성 - 트랜잭션 간의 간섭이 없도록 보장
지속성 - 트랜잭션 성공시 변경 사항은 영구적으로 저장되어야함
인덱스(Index)
데이터베이스에서 특정 열(컬럼)의 값을 기반으로 빠르게 데이터를 찾을 수 있도록 도와주는 데이터 구조
인덱스는 테이블의 특정 열에 대한 정렬된 키-값 쌍의 집합으로 구성
이를 통해 데이터베이스 관리 시스템(DBMS)은 검색 속도를 향상
인덱스를 모든컬럼에 넣으면 어떻게되나?
DB크기 증가
insert update delete작업에 부가적인 오버헤드 유발. 데이터 변경작업의 속도가 느려짐
쿼리 실행 계획이 복잡해져 최적화가 어려워잠
인덱스는 메모리에 저장되기때문에 메모리 사용량이 급증할수있음
기본키와 외래키
기본키
기본키는 테이블 내에서 각 행을 유일하게 식별하는 열
각 행은 반드시 기본키 값을 가져야 하며, 이 값은 중복되지 않아야 한다.
NULL 값을 허용하지 않음
테이블 내에서 각 행을 고유하게 식별하기 위해 사용
다른 테이블과의 관계를 설정할 때 외래키로 사용될 수 있음
외래키
외래키는 다른 테이블의 기본키와 관련된 열.
한 테이블의 외래키는 다른 테이블의 기본키와 동일한 값을 가질 수 있다.
외래키는 참조 무결성을 유지하기 위해 사용.
테이블 간의 관계를 설정하고 유지하기 위해 사용.
외래키를 사용하여 참조된 테이블의 행을 식별하고 연결할 수 있음.
1계층 물리 케이블 허브 하드웨어 | 비트와 전기적신호 전송
2계층 데이터링크 MAC 물리단계의 비트를 프레임형태로 조작, 오류검출과 흐름제어
3계층 네트워크 패킷의 경로설정, 라우팅 수행 IP주소를 사용하여 경로결정
4계층 전송 데이터전송, 흐름제어와 오류복구기능
사용자 입력 및 요청(http메소드)
브라우저는 DNS(도메인네임시스템) 해석해서 서버연결 및 HTTP요청을 함
서버 응답
HTML 파싱 및 렌더링
페이지렌더링
사용자의 이벤트에 대해 상호작용
보안및 보호
운영체제의 역할
컴퓨터의 핵심소프트웨어로써 하드웨어와 응용소프트웨어간의 효율적이고 안정적인 상호작용 담당
프로세스 - 메모리상에서 실행중인 프로그램 - 자신만의 고유 공간과 자원을 할당받아 사용 - 음식점
여러프로세스 동시실행? -> 멀티프로세스
쓰레드 - 프로세스 안에서 실행되는 작업단위 - 다른 쓰레드와 공간과 자원을 공유하면서 사용 - 직원
배열과 리스트
배열 - 연속적인 메모리 위치에 데이터를 저장하는 자료구조
-장점 순서를 유지할 수 있고 접근이 빠름
-단점 배열의 크기가 고정적이기 때문에 데이터가 많아지면 재할당 해야함
💡 **배열의 시간복잡도**
- 데이터 읽기, 수정 : O(1)
- 데이터 추가, 삭제 : O(N)
- 예외 : 배열에 빈 공간이 존재하는걸 허용하며 짜는 경우라면 마지막 데이터의 추가, 삭제는 O(1)
리스트(LinkedList) - 노드로 연결된 데이터를 저장하는 자료구조
💡 **리스트.Create 시간복잡도**
- 리스트의 중간에 데이터를 넣을 경우 : O(N)
- 맨 앞이나 맨 뒤에 넣을 경우 : O(1) - 일반적으로 이 경우가 많음
💡 **리스트.Read/Update 시간복잡도**
- 맨앞이나 맨 뒤의 데이터를 확인하거나 바꿀 경우 : O(1)
- 중간의 데이터를 확인하거나 바꿀 경우 : O(N) - 일반적으로 이 경우가 많음
💡 **리스트.Delete 시간복잡도**
- 중간의 데이터를 삭제할 경우 : O(N)
- 맨앞이나 맨 뒤에 데이터를 확인하거나 바꿀 경우 : O(1) - 일반적으로 이 경우가 많음
❓ **배열은 언제쓰고 리스트는 언제쓸까?**
- 리스트
- 일반적으로 데이터의 추가, 삭제가 많은 경우 리스트를 사용하는 것이 효율이 좋다
- 배열
- 데이터가 자주 추가, 삭제 되지 않고, 읽고 수정하는 경우가 많을 때 배열을 사용하는 것이 효율이 좋다
인접한 두 요소를 비교하여 큰 값을 오른쪽으로 이동시키는 방식 (시간복잡도 : O(n^2))
for(let j=0; j<arr.length-1; j++){
for(let i=0; i<arr.length-1; i++){
if(arr[i]>arr[i+1]){
let x = arr[i+1];
arr[i+1] = arr[i];
arr[i] = x;
}
}//1~3과정임.
}
주어진 리스트에서 최소값을 찾아 맨 앞에 위치한 값과 교체 (시간복잡도 : O(n^2))
function selectionSort(arr) {
const n = arr.length;
for (let i = 0; i < n - 1; i++) {
// 현재 위치부터 끝까지의 최소값 인덱스 찾기
let minIndex = i;
for (let j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// 현재 위치와 최소값 위치 교체
if (minIndex !== i) {
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
}
}
return arr;
}
리스트를 반으로 나눈 후 각각을 재귀적으로 정렬하고 정렬된 두 리스트를 합쳐 전체 리스트를 정렬(시간복잡도(O(n log n))
function mergeSort(arr) {
const n = arr.length;
// 리스트가 1개 이하의 요소를 가질 때는 이미 정렬된 것으로 간주
if (n <= 1) {
return arr;
}
// 리스트를 절반으로 나누기
const middle = Math.floor(n / 2);
const left = arr.slice(0, middle);
const right = arr.slice(middle);
// 나눈 부분 리스트를 재귀적으로 정렬
const leftSorted = mergeSort(left);
const rightSorted = mergeSort(right);
// 정렬된 부분 리스트를 합병하여 정렬된 리스트 생성
return merge(leftSorted, rightSorted);
}
function merge(left, right) {
let result = [];
let leftIndex = 0;
let rightIndex = 0;
// 두 부분 리스트를 비교하며 더 작은 값을 결과에 추가
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] < right[rightIndex]) {
result.push(left[leftIndex]);
leftIndex++;
} else {
result.push(right[rightIndex]);
rightIndex++;
}
}
// 남은 요소들을 결과에 추가
return result.concat(left.slice(leftIndex), right.slice(rightIndex));
}
피벗(pivot)을 선택하고 피벗을 기준으로 작은 값은 왼쪽, 큰 값은 오른쪽으로 나눔(시간복잡도 평균 : O(n log n) 최악 : O(n^2)(피벗이 항상 최솟값 또는 최댓값일 경우))
function quickSort(arr) {
if (arr.length <= 1) {
return arr; // 배열의 크기가 1 이하이면 이미 정렬된 것으로 간주
}
const pivot = arr[0]; // 첫 번째 요소를 피벗으로 선택
const left = [];
const right = [];
for (let i = 1; i < arr.length; i++) {
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
// 왼쪽과 오른쪽 부분 리스트에 대해 재귀적으로 퀵 정렬 수행 후 합병
return quickSort(left).concat(pivot, quickSort(right));
}
JWT 웹에서 정보를 안전하게 전송하기위한 표준방법 사용자 정보나 특정 서비스의 정보를 담을 수 있음
구조
Header - JSON형태 토큰 타입과 해시알고리즘 정보 포함
Payload - 클레임(토큰발급자,만료시간)
Signature - 비밀키를 사용하여 생성
토큰이 탈취될경우 해킹 위험에 노출 -> 엑세스토큰의 만료시간 설정, 리프레시토큰 사용
민감한 정보는 담지않아야함
HTTPS 사용권장
리프레시토큰 엑세스토큰 만료시 리프레시토큰을 사용하여 새로운 액세스토큰 발급