티스토리 뷰
Hoisting(끌어올려진다.)
자바스크립트가 코드를 읽어올 때 각 Scope(구역)에 들어있는 var, function과 같은 키워드로 선언된 코드는 아래와 같이 동작합니다.
- 실제 코드
console.log(name); // Print: undefined
var name = '강승현';
- 위 코드를 실행했을때 선언되지 않은 변수를 미리 참조했기 때문에 첫번째 줄에서 참조 에러가 발생해야 하는데 실제로는 발생하지 않습니다. 어떻게 된것일까요?
- 바로 Hoisting 이라고 불리우는 동작 때문인데요, var, function 키워드로 선언하면 아래와 같이 동작한다고 이해하시면 됩니다.
- Hoisting 적용 예시
(실제로 이렇게 변환되는것은 아니며, 대략 아래 코드처럼 동작한다는 의미입니다.)
var name;
0console.log(name); // Print: undefined
name = '강승현';
- 이렇게 선언된 변수나 함수가 함수의 스코프 최상단으로 끌어올려진다는 의미입니다.
- 사실은 var, function 뿐만 아니라 let, const, class도 내부적으로는 모두 호이스팅됩니다.
- 그러나 다른 사람들이 let, const가 호이스팅되지 않는다고 말하는 이유는, 자바스크립트 내부에 TDZ라는 (개념)영역이 존재하며 TDZ 영역에 존재하는 변수는 접근이 불가능한데, 실제 변수 선언이 실행되는 구문이 실행되기 전에는 const, let, class로 선언된 이름은 모두 TDZ에 존재하여 참조 에러를 발생시키는것입니다.
-
- 만약 아직 이해가 어렵다면 var 키워드를 사용하면 호이스팅이 일어나서 안좋다. 라는것만 기억하셔도 충분합니다. TDZ의 보호를 받고 있지 않은 키워드인 var를 사용하는것은 변수의 값이 언제 바뀔지도 모르며 스파게티 코드를 만드는 주범이 될 수 있으므로 절대로 지양해야 합니다 😉
동기(Sync)와 비동기(Async)에 대한 개념
-
- 일반적으로 "동기로 실행된다" 라고 함은, 먼저 실행된 코드의 결과가 나올때까지 대기하는것을 말합니다.
- 놀이기구를 생각하면 쉽습니다.
- 정원이 30명인 놀이기구가 있다고 가정합니다. 놀이기구를 한번 태우는데 약 5분이 걸린다고 가정하면 놀이기구를 막 태우기 시작한 시점에서는 대기자 모두 5분이 지나 이미 놀이기구에 탑승했던 사람들이 다 내리기 전까지는 탑승을 할 수 없습니다. 이것은 놀이기구 탑승/하차가 동기적으로 관리된다고 볼 수 있습니다.
- 일반적으로 "비동기로 실행된다" 라고 함은, 실행된 순서와 관계 없이 결과가 나오는것을 말합니다.
- 정원이 최대 30명인 맛집이 있다고 가정합니다. 입장 순서는 선착순이고 퇴장 순서는 다 먹은 사람이 바로 나올 수 있습니다. 다 먹은 사람이 나오면 나온 사람 수 만큼 다시 입장 할 수 있습니다. 사람마다 먹는 시간은 모두 다릅니다. 이것은 입/퇴장이 비동기적으로 처리된다고 볼 수 있습니다.
- 일반적으로 "동기로 실행된다" 라고 함은, 먼저 실행된 코드의 결과가 나올때까지 대기하는것을 말합니다.
Blocking Model & Non-Blocking Model(제어권차이)
-
- Blocking Model이란, 코드의 실행이 끝나기 전까지 실행 제어권을 다른곳에 넘기지 않아 다른 작업을 하지 못하고 대기하는 것을 말합니다.
- Non-blocking Model이란, 코드의 실행이 끝나지 않아도 실행 제어권을 다른곳에 넘겨 다음 코드가 실행될 수 있는것을 말합니다.
- 동기, 비동기와 뭐가 다른걸까?
- 제어권을 넘기면(Non-blocking) 다른 코드도 실행될 수 있으므로 비동기 처리가 가능하지만 제어권을 넘기지 않으면(Blocking) 비동기 처리가 가능한 환경이어도 비동기 처리가 불가능합니다.
- 자바스크립트는 Async + Non-blocking Model을 채용하여 현재 실행중인 코드의 실행이 끝나지 않아도 다음 코드를 호출합니다.
- 결론적으로 자바스크립트는 Non-blocking model을 가지며 각 명령이 순서대로 실행될 수 있게 구현되어 있지만, Non-blocking model에 의해 명령이 아닌 모든 함수는 비동기적으로 실행됩니다.
- 예시 (setTimeout은 특정 시간 뒤에 함수를 실행해주는 역할입니다.)
function first() {
console.log('First');
}
setTimeout(first, 1000); // 1000ms(1초) 뒤에 first 함수를 실행해준다.
console.log('Middle');
console.log('Last');
// Print: Middle
// Last
// First
-
- 만약 자바스크립트가 Non-blocking model이 아니었다면 위 코드는 1초를 기다려서 first 함수를 먼저 호출하여 'First'를 출력한 뒤, 'Middle', 'Last' 순서로 출력해야 합니다.
Promise
-
- 자바스크립트에서 비동기 처리를 동기로 처리할 수 있게 돕는 객체 유형입니다.
- 이 객체를 이용하면 여러분은 Non-blocking model을 가진 자바스크립트에서도 비동기 처리를 아주 손쉽게 할 수 있습니다.
- Promise 생성자 인터페이스
- executor에는 함수만 올 수 있으며 인자로 resolve, reject가 주입됩니다.
new Promise(executor);
// 예제
new Promise((resolve, reject) => {
// 명령문
});
-
- 프로미스의 상태
- 프로미스는 반드시 3가지 상태를 지니며, 대기(Pending) 상태가 아니라면 Promise의 연산이 이미 끝난 상태로 볼 수 있습니다.
- 대기(Pending): 이행하거나 거부되지 않은 초기 상태.
- 이행(Fulfilled): 연산이 성공적으로 완료됨.
- 거부(Rejected): 연산이 실패함.
프로미스가 만들어 질 때 executor가 실행되며, executor에서 resolve 함수가 호출되기 전까지 firstPromise.then(...) 안에 있는 코드를 실행하지 않습니다.
이렇게 executor 가 실행되어 resovle된 프로미스를 Fulfilled Promise라고도 부릅니다.
const timerPromise = new Promise((resolve, reject) => { // 이곳에 정의된 함수가 executor
setTimeout(() => {
console.log('First');
resolve();
}, 1000);
});
// 이 시점에서 timerPromise는 Fulfilled Promise라고 부를 수 있다.
timerPromise.then(() => {
console.log('Middle');
console.log('Last');
});
// Print: First
// Middle
// Last
Promise.catch
프로미스 안에서 에러가 throw 되거나 reject되면 catch 메서드에 작성한 함수가 실행됩니다.
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);
});
// Print: '에러 발생! Error!!'
-
- Promise.then 더 알아보기
1. Promise에서 resolve 된 값 이용하는 방법
const firstPromise = new Promise((resolve, reject) => {
resolve('First');
});
firstPromise.then((value) => {
console.log(value);
});
// Print: 'First'
2. Promise.resolve 함수 이용
프로미스가 값을 반환하는 경우 반환되는 값은 항상 프로미스로 감싸져 있습니다!
const firstPromise = Promise.resolve('First');
firstPromise.then((value) => {
console.log(value);
});
// Print: 'First'
3. Promise.then으로 함수형 프로그래밍 체험하기
이것이 가능한 이유는 console.log라는 함수 뒤에 괄호를 사용해서 함수를 호출하지 않고, 함수를 그대로 then에 넘겼기 때문입니다.
const firstPromise = Promise.resolve('First');
firstPromise.then(console.log);
// Print: 'First'
4. Promise.then으로 함수형 프로그래밍 체험하기 2
const countPromise = Promise.resolve(0);
function increment(value) {
return value + 1;
}
const resultPromise = countPromise.then(increment).then(increment).then(increment);
resultPromise.then(console.log);
// Print: 3
-
- 이 외에도 유용한 프로미스 함수
비동기 함수 (Async Function)
-
- 특징
비동기 함수는 일반 함수나 화살표 함수와 아주 비슷하지만 딱 두가지만 다릅니다.
- 비동기 함수의 결과 값은 항상 Promise 객체로 resolve된다.
- 비동기 함수 안에서만 await 연산자를 사용할 수 있다. (바로 아래에서 배웁니다!)
이 두가지 특징을 제외하면 기존처럼 일반 함수나, 화살표 함수처럼 사용할 수 있습니다. 아래처럼요. 아래 세가지 함수 모두 결과 값은 Promise로 받습니다.
// 비동기 + 일반 함수
async function 함수이름() {
// 명령문
}
// 비동기 + 익명 함수
async function() {
// 명령문
}
// 비동기 + 화살표 함수
async () => {
// 명령문
}
-
- 이러한 특징은 마치 아래처럼 작성하는것과 굉장히 비슷합니다.
function 함수이름() {
return Promise.resolve('값');
}
// 위와 아래의 함수는 같은 동작을 보여준다.
async function 함수이름2() {
return '값';
}
함수이름();
// Print: Promise { '값' }
함수이름2();
// Print: Promise { '값' }
-
- 그럼 비동기 함수는 왜 쓸까요?
아래에서 배울 await 연산자를 비동기 함수 안에서만 사용할 수 있는데요, 이를 활용하면 문법이 훨씬 간결해질 수 있습니다.
덕분에 비동기 함수는 여러분이 비동기 프로그래밍을 하게 되면 즐겨 사용하는 함수 유형중 하나가 될 것 입니다. 😇
- new Promise(executor) 코드로 프로미스를 직접 생성하면 executor가 바로 실행되는것과 달리, 비동기 함수는 함수가 실행되기 전까지 프로미스를 생성하지 않습니다.
🔥 자바스크립트가 실제로 비동기처럼 실행될 수 있는 원리는 상당히 복잡하며 설명이 너무x10 길어지기 때문에 생략합니다. 궁금하시다면 Callback, Event loop, Call stack에 대해 알아보시는것이 좋습니다.
await 연산자
-
- await 연산자를 사용하면 Promise가 fulfill되거나 rejected될 때 까지 함수의 실행을 중단하고 기다릴 수 있습니다. Promise의 연산이 끝나면 함수에서 반환한 값을 얻을 수 있습니다.
- await 연산자는 async 함수 안에서만 사용할 수 있습니다.
- 인터페이스
const result = await 값;
-
- "값" 에는 Promise가 아닌 다른 값도 들어갈 수 있습니다. 아래처럼요! Promise가 아니라면 기다리지 않고 해당 값 자체를 그대로 반환합니다.
async function 함수이름() {
const result = await 'Test!';
console.log(result);
}
함수이름();
// Print: 'Test!';
모든 비동기 함수는 promise를 반환한다.
await 함수는 뒤에 값이 promise인지 애매할때 넣어주면 된다.
async 함수의 반환 값은 무엇일까요?
🚀 정답
async 함수의 결과값은 항상 Promise 객체로 resolve 되기 때문에 값은 동일합니다.
async 함수 안에서 Promise 객체를 반환하면 어떤 결과가 나올까요?
🚀 정답
async 함수 안 어딘가에서 에러가 발생하지 않았다면 async 함수의 반환 값은 무조건 Promise 객체입니다!
async function getMyName() {
return Promise.resolve('강승현');
}
const result = getMyName();
result.then((myName) => {
console.log(myName);
});
강승현이 리턴됨
'항해 > 주특기 1주차' 카테고리의 다른 글
[node js] 2주차 - 2 (0) | 2022.01.23 |
---|---|
[node js] 2주차 - 1 (0) | 2022.01.22 |
[node js] 1주차 - 마음가짐 (0) | 2022.01.22 |
[node js] 1주차 - 2 (0) | 2022.01.22 |
[node js] 1주차 - 1 (0) | 2022.01.21 |