01. 동기(Sync) & 비동기 (Async)
- 동기에 대한 개념
- 먼저 실행된 코드의 결과가 나올때까지 대기하는 것을 말한다.
- 예시) 정원이 한번 태우면 5분이 걸리는 놀이기구에 30명이 정원이라 생각해보자. 5분 뒤에 탑승했던 사람들이 다 내리기 전까지는 탑승할 수 없으니 놀이기구 탑승/하차가 동기적으로 관리된다고 볼 수 있다.
- 비동기에 대한 개념
- 실행된 순서와 관계 없이 결과가 나온다.
- 예시) 정원이 30명인 맛집에 들어가기 위해 대기 손님이 있다고 가정하자. 식사를 마친 사람은 언제든 바로 나올 수 있으며 나온 사람의 숫자만큼 다시 입장이 가능하다. 따라서 맛집 입/퇴장이 비동기적으로 처리된다.
- Blocking Model & Non-Blocking Model
- Blocking Model - 코드의 실행이 끝나기 전까지 실행 제어권을 다른 곳에 넘기지 않아 다른 작업을 하지 못하고 대기하는 것을 말한다. 비동기 처리가 가능한 환경이어도 비동기 처리가 불가능하다.
- Non-Blocking Model - 코드의 실행이 끝나지 않아도 실행 제어권을 다른 곳에 넘겨 다음 코드가 실행될 수 있다. 다른 코드도 실행될 수 있으므로 비동기 처리가 가능하다.
- JavaScript는 Async + Non-Blocking Model을 채용, 즉 현재 실행 중인 코드의 실행이 끝나지 않아도 다음 코드를 호출한다.
- 결론적으로 JS는 각 명령들이 순서대로 실행될 수 있게 구현되어 있다. 그러나 Non-Blocking Model에 의해 동기적 명령이 아닌 모든 함수는 비동기적으로 실행된다.
- 예시)
function first() {
console.log('First');
}
setTimeout(first, 1000); // 1000ms(1초) 뒤에 first 함수를 실행해준다.
console.log('Middle');
console.log('Last');
- setTimeout(first, 1000): 1초 뒤에 first()가 실행되도록 명령
- Middle, Last 문자열이 출력된다.
- 1초가 지난 뒤 First 문자열 출력
==> JS가 Blocking Model이었다면 예시 코드는 1초를 기다린 이후 first()함수를 먼저 실행해서 First, Middle, Last 순서로 출력됐을 것이다.
- 프로미스(Promise)
- JS에서 비동기 처리를 동기로 처리할 수 있게 돕는 Built-in 객체 유형
- Promise 생성자 인터페이스 - executor에는 함수만 올 수 있으며 인자로 resolve, reject가 주입된다.
- executor는 Promise의 실행 함수, Promise가 만들어질 때 자동으로 실행된다.
- Promise가 연산을 언제 종료하는지 상관하지 않고, resolve, reject중 하나를 무조건 호출해야 한다.
- Promise의 상태
- 대기(Pending): 이행하거나 거부되지 않은 초기 상태.
- 이행(Fulfilled): 연산이 성공적으로 완료
- 거부(Rejected): 연산이 실패함
- Promise가 만들어 질 때 executor가 실행된다. executor에서 resolve 함수가 호출되기 전까지 firstPromise,tne(...) 안에 있는 코드를 실행하지 않는다. executor가 실행되어 resolve된 프로미스르 Fulfilled Promise라고 부른다.
async function main() {
const timerPromise = new Promise((resolve, reject) => { // 이곳에 정의된 함수가 executor
setTimeout(() => {
console.log('First');
resolve();
}, 1000);
});
// 이 시점에서 timerPromise는 Fulfilled Promise라고 부를 수 있다.
timerPromise.then(() => {
console.log('Middle');
console.log('Last');
});
}
main()
- ==> 1초를 기다렸다 First, Middle, Last 순서로 출력된다.
- Promise.then ==> resolve가 실행 된 경우 then 메서드에 작성된 함수가 실행된다.
async function main() {
const resolvePromise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('First');
resolve('Resolve!'); // resolve를 실행할 때, 안에 데이터를 넣어줄 수 있습니다.
}, 1000);
});
resolvePromise.then((data) => {
console.log('Middle');
console.log('Last');
console.log(data);
})
}
main()
- ==> 1초 뒤에 First, Middle, Last, Resolve!가 순서대로 출력된다.
- Promise.catch ==> 에러가 throw 되거나 reject가 실행되면 catch메서드에 작성한 함수가 실행된다.
async function main() {
const errorPromise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('First');
reject('Error!!'); // 직접 reject를 실행하면 프로미스에서 에러가 발생한것으로 간주됩니다.
}, 1000);
});
errorPromise.then(() => {
console.log('Middle');
console.log('Last');
}).catch((error) => {
console.log('에러 발생!', error);
});
}
main()
- ==> 1초 뒤에 First, 에러 발생! Error!! 가 출력된다.
- 비동기 함수(Async Function)
- 일반 함수나 화살표 함수와 아주 비슷하지만 딱 두가지만 다르다.
- 결과 값은 항상 Promise 객체로 resolve된다.
- await 연산자를 사용할 수 있다.
- 일반 함수나 화살표 함수와 아주 비슷하지만 딱 두가지만 다르다.
// 비동기 + 일반 함수
async function 함수이름() {
// 명령문
}
// 비동기 + 익명 함수
async function() {
// 명령문
}
// 비동기 + 화살표 함수
async () => {
// 명령문
}
- ==> 세가지 모두 결과 값은 Promise로 받는다.
- new Promise(executor) 코드로 Promise를 직접 생성하면 executor가 바로 실행되는 것과 달리, 비동기 함수는 함수가 실행되기 전까지 Promise를 생성하지 않는다.
- JS는 Callback, Event loop, Call stack을 이용해 실제로 비동기처럼 실행될 수 있다.
- await 연산자
- Promise가 fulfill 상태가 되거나 rejected될 때까지 함수의 실행을 중단하고 기다릴 수 있다.
- Promise의 연산이 끝나면 함수에서 반환한 값을 얻을 수 있다.
- Async 함수 안에서만 사용할 수 있다.
function setTimeoutFunc(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(time, "에 해당하는 시간이 지났습니다.")
resolve()
}, time)
})
}
async function main() {
console.log("시작 되었습니다.")
await setTimeoutFunc(1000)
console.log("종료 되었습니다.")
}
main()
- ==> '시작 되었습니다' 출력 1초 뒤에 '1000에 해당하는 시간이 지났습니다.' '종료 되었습니다.' 순서대로 출력
02. 객체 리터럴
- 객체란? ==> JS의 데이터 타입은 크게 원시 타입과 객체 타입으로 분류된다.
- 원시 타입: 단 하나의 값, 원시 타입의 값은 변경이 불가능 한 값
- 객체 타입: 다양한 타입의 값을 하나의 단위로 구성한 복합적인 자료 구조, 객체 타입의 값은 변경 가능한 값
- JS는 객체(Object) 기반의 프로그래밍 언어, JS를 구성하는 거의 모든 것은 객체로 구성, 객체는 0이상의 프로퍼티로 구성된 집합, 하나의 프로퍼티는 Key와 Value로 구성된다.
- 객체 리터럴?
- 리터럴: 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기법
- 객체 리터럴: 객체를 생성하기 위한 표기법
- 객체 리터럴은 객체를 생성하기 위해 Class를 먼저 선언하고 new 연산자와 함께 생성자를 호출할 필요가 없이 일반적인 숫자, 문자열을 만드는 것과 유사하게 객체를 생성할 수 있다.
- 객체 리터럴은 { }내에 0개 이상의 프로퍼티를 정의해서 선언한다.
let objectLiteral = {
key: 'Value',
helloWorld: function () {
return "Hello world";
}
};
==> 객체 리터럴은 원시타입뿐만 아니라 함수도 들어갈 수 있다.
- 프로퍼티(Property)란? ==> 객체의 상태를 나타내는 값(Data)
- 프로퍼티(Property): Key-Value
const human = {
// 프로퍼티 키: 'name', 프로퍼티 값: 'YoonSoo'
name: 'YoonSoo',
// 프로퍼티 키: 'human age', 프로퍼티 값: 28
'human age': 28
}
==> 일반적으로 Key는 따옴포를 사용하지 않는다. But 띄어쓰기나 실제로 변수로 할당할 수 없는 것을 Key에 할당할 때 사용한다.
- 메서드(Method)란?
- 프로퍼티를 참조하고 조작할 수 있는 동작(behavior)을 나타낸다.
- 객체의 프로퍼티 값이 함수로 구성되어 있을 경우 메서드(Method)라고 부른다.
let objectLiteral = {
key: 'Value', // 프로퍼티
helloWorld: function () { // 메서드
return "Hello world";
}
};
console.log(objectLiteral.helloWorld()); // Hello world
- 사칙 연산을 하는 객체 만들기
let calculator = {
add: function(a,b) {return a+b},
sub: function(a,b) {return a-b},
mul: function(a,b) {return a*b},
div: function(a,b) {return a/b}
}
console.log(calculator.add(3,2)) //5
console.log(calculator.sub(3,2)) //1
console.log(calculator.mul(3,2)) //6
console.log(calculator.div(3,2)) //1.5
03. Error handling
- Error handling이란? ==> Error를 관리하는 방법, 예상치 못한 상황에 대처하는 방식
- 예상할 수 있는 에러와 예상치 못한 에러로 구분, 일반적으로 어플리케이션을 설계할 때에는 예상치 못한 에러 상황이 더욱 많이 일어날 것으로 가정해야 한다.
- 작성한 코드에서 예상치 못한 에러가 일어날 가능성 언제나 존재한다. 따라서 이런 에러 상황을 대비해 언제든지 처리할 수 있어야 한다.
- try / catch
- 서버에서 에러가 발생하지 않게 하기 위해서 예외 처리를 진행한다. 일반적으로 try-catch문을 사용한다.
const users = ["Lee", "Kim", "Park", 2];
try {
for (const user of users) {
console.log(user.toUpperCase());
}
} catch (err) {
console.error(`Error: ${err.message}`);
}
// LEE
// KIM
// PARK
// Error: user.toUpperCase is not a function
==> toUpperCase()는 문자열(String)을 대문자로 변경해주는 메서드. 문자열이 아닌 값이 들어온다면 error가 발생한다. 이렇게 예상치 못한 에러에 대처하기 위해서 try - catch문으로 코드 전체를 감싸 에러가 발생하더라도 프로그램이 멈추지 않고 에러를 기록할 수 있다.
- throw
- 프로그래머의 입장에서 에러는 고의로 사용하기도 한다.
- 예시) 은행 어플리케이션의 현금 인출 서비스를 만든다고 할 때, 계좌의 잔고가 요청받은 금액보다 적다면 현금 인출을 막고 예외를 발생시켜야한다. 이럴때 throw를 사용한다.
throw를 호출하면 그 즉시 현재 실행되고 있는 함수는 실행을 멈추게 된다.
function withdraw(amount, account) {
if (amount > account.balance)
throw new Error("잔고가 부족합니다.");
account.balance -= amount;
console.log(`현재 잔고가 ${account.balance}남았습니다.`); // 출력되지 않음
}
const account = { balance: 1000 };
withdraw(2000, account);
// Error: 잔고가 부족합니다.
==> 잔고가 더 적기때문에 error를 띄우게 된다.
- finally
- 어떤 '자원'을 계속 가지고 있으면 무의미한 메모리를 차지하게 될 경우 에러 여부와 상관없이 일정 시점에서 해당 '자원'을 삭제하는 문법이다.
- finally는 에러가 발생했느지 여부와 상관없이 언제든지 실행이 가능하다.
function errorException(isThrow) {
try {
console.log('자원을 할당하였습니다.');
if (isThrow) throw new Error();
} catch (error) {
console.log('에러가 발생했습니다.');
} finally {
console.log('자원을 제거하였습니다.');
}
}
errorException(false);
// 자원을 할당하였습니다.
// 자원을 제거하였습니다.
errorException(true);
// 자원을 할당하였습니다.
// 에러가 발생했습니다.
// 자원을 제거하였습니다.
==> false로 error가 발생하지 않아도, true로 error가 발생하여도 finally는 언제든 실행 가능하다.
04. 클래스(Class)
- 클래스란? ==> 현실과 비슷한 개념(객체)을 나타내기 위한 도구
- 클래스는 미리 정의해놓으면 필요할 때마다 해당 클래스로 동일한 틀을 가진 객체를 만들 수 있다.
==> 인스턴스(Instance): 동일한 클래스를 이용해 생성한 객체
class User {
}
const user = new User();
user.name = "YoonSoo";
user.age = 28;
user.tech = "Node.js";
console.log(user.name); // YoonSoo
console.log(user.age); // 28
console.log(user.tech); // Node.js
- 생성자(Constructor)
- 미리 정의한 클래스를 기반으로 인스턴스를 생성할 때 JS 내부에서 호출되는 메서드
class User {
constructor(name, age, tech) { // User 클래스의 생성자
this.name = name;
this.age = age;
this.tech = tech;
}
}
const user = new User("YoonSoo", 28, "Node.js"); // user 인스턴스 생성
console.log(user.name); // YoonSoo
console.log(user.age); // 28
console.log(user.tech); // Node.js
- this와 프로퍼티(Property)
- Constructor 바디에서 this 키워드를 사용
- this는 클래스를 사용해 만들어 질 객체 자신을 의미, this 뒤에 붙는 name, age, tech는 클래스를 이용해서 만들어질 객체의 Property
class User {
constructor(name, age, tech) { // User 클래스의 생성자
this.name = name;
this.age = age;
this.tech = tech;
}
}
const user = new User("YoonSoo", "28", "Node.js"); // user 인스턴스 생성
console.log(user.name); // YoonSoo
console.log(user.age); // 28
console.log(user.tech); // Node.js
==> 생성자를 이용해 인자값을 입력받아 class 내부변수에 저장한다.
- 메서드(Method)
- Property 값이 함수일 경우 일반 함수와 구분하기 위해 메서드(Method)라고 부른다.
- 메서드는 객체(Object)에 묶여 있는 함수를 의미한다.
class User {
constructor(name, age, tech) { // User 클래스의 생성자
this.name = name;
this.age = age;
this.tech = tech;
}
getName() { return this.name; } // getName 메서드
getAge() { return this.age; } // getAge 메서드
getTech() { return this.tech; } // getTech 메서드
}
const user = new User("YoonSoo", "28", "Node.js"); // user 인스턴스 생성
console.log(user.getName()); // YoonSoo
console.log(user.getAge()); // 28
console.log(user.getTech()); // Node.js
- 상속이란?
- 일반적으로 클래스의 인스턴스는 선언한 클래스의 기능을 모두 상속
- 상속을 이용하면 부모 클래스와 자식 클래스로 나뉠 수 있는데, 메서드 내부 변수 같은 정보를 자식 클래스에게 할당해줄 수 있다.
class User { // User 부모 클래스
constructor(name, age, tech) { // 부모 클래스 생성자
this.name = name;
this.age = age;
this.tech = tech;
}
getTech() { return this.tech; } // 부모 클래스 getTech 메서드
}
class Employee extends User { // Employee 자식 클래스
constructor(name, age, tech) { // 자식 클래스 생성자
super(name, age, tech); // super는 부모 클래스의 생성자를 호출
}
}
const employee = new Employee("YoonSoo", "28", "Node.js");
console.log(employee.name); // YoonSoo
console.log(employee.age); // 28
console.log(employee.getTech()); // 부모 클래스의 getTech 메서드 호출: Node.js
==> super키워드는 this와 같이 식별자처럼 참조할 수 있는 키워드다. super 키워드를 호출하면 부모 클래스의 생성자를 호출한다. super 키워드를 참조하면 부모 클래스의 메서드를 호출한다.
- Quiz
- Unit 클래스를 만든다.
- 클래스 생성자에서 내부변수 name, hp를 정의한다.
- healing, damaged 메서드를 정의한다.
- healing 메서드는 hp를 올릴 수 있고 hp가 100이 넘을 경우 더이상 회복되지 않는다.
- damaged 메서드는 hp를 감소 시킬 수 있고 hp가 0이 넘을 경우 더이상 감소되지 않는다.
- hp가 0이 되었을 경우 더이상 healing 메서드와 damaged 메서드가 동작하지 않는다.
class Unit {
constructor(name, hp) {
this.name = name;
this.hp = hp;
}
healing(heal) {
if(this.hp<=0) return
this.hp += heal;
if(this.hp>=100) this.hp = 100;
}
damaged(damage) {
if(this.hp<=0) return
this.hp -= damage
if(this.hp<=0) this.hp = 0
}
}
const unit = new Unit('YoonSoo', 100)
unit.damaged(30) // 70
unit.healing(10) // 80
unit.damaged(80) // 0
unit.healing(100) // 0
console.log(unit.hp) // 0
'JavaScript Dev. > Node.js' 카테고리의 다른 글
Package Manager 란? (0) | 2023.04.22 |
---|---|
HTTP / Web Server (0) | 2023.04.22 |
Node.js (0) | 2023.04.21 |
RESTful (0) | 2023.04.20 |
Express 미들웨어 (0) | 2023.04.20 |