
특정 코드의 실행이 완료될 때까지 기다리고 난 후 다음 코드를 수행하는 것을 의미
특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드들을 수행하는 것 을 의미
setTimeout(callback, millisecond)setTimeout(function () {
console.log('1초 후 실행');
}, 1000);
// 123clearTimeout(timerId)setTimeout 타이머를 종료const timer = setTimeout(function () {
console.log('10초 후 실행');
}, 10000);
clearTimeout(timer);
// setTimeout이 종료됨.setInterval(callback, millisecond)setInterval(function () {
console.log('1초마다 실행');
}, 1000);
// 345clearInterval(timerId)setInterval 타이머를 종료const timer = setInterval(function () {
console.log('1초마다 실행');
}, 1000);
clearInterval(timer);
// setInterval이 종료됨.CallbackCallback 함수를 활용하는 방법이 있다. Callback 함수를 통해 비동기 코드의 순서를 제어할 수 있습니다.const printString = (string, callback) => {
setTimeout(function () {
console.log(string);
callback();
}, Math.floor(Math.random() * 100) + 1);
};
const printAll = () => {
printString('A', () => {
printString('B', () => {
printString('C', () => {});
});
});
};
printAll();
console.log(
`아래와 같이 Callback 함수를 통해 비동기 코드의 순서를 제어할 수 있습니다!`
);
// 출력 ↓
// 아래와 같이 Callback 함수를 통해 비동기 코드의 순서를 제어할 수 있습니다!
// A
// B
// C
Callback HellCallback 함수를 통해 비동기 코드의 순서를 제어할 수 있지만 코드가 길어질수록 복잡해지고 가독성이 낮아지는 Callback Hell이 발생하는 단점이 있다.
const printString = (string, callback) => {
setTimeout(function () {
console.log(string);
callback();
}, Math.floor(Math.random() * 100) + 1);
};
const printAll = () => {
printString('A', () => {
printString('B', () => {
printString('C', () => {
printString('D', () => {
printString('E', () => {
printString('F', () => {
printString('G', () => {
printString('H', () => {
printString('I', () => {
printString('J', () => {
printString('K', () => {
printString('L', () => {
printString('M', () => {
printString('N', () => {
printString('O', () => {
printString('P', () => {});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
};
printAll();
console.log(
`아래와 같이 Callback 함수를 통해 비동기 코드의 순서를 제어할 수 있지만 코드가 길어질 수록 복잡해지고 가독성이 낮아지는 Callback Hell이 발생하는 단점이 있습니다.`
);
// 출력 ↓
// 아래와 같이 Callback 함수를 통해 비동기 코드의 순서를 제어할 수 있지만 코드가 길어질 수록 복잡해지고 가독성이 낮아지는 Callback Hell이 발생하는 단점이 있습니다.
// A
// B
// ...
// O
// P (차례대로 호출)
Promisenew PromisePromise는 class이기 때문에 new 키워드를 통해 Promise 객체를 생성Promise는 비동기 처리를 수행할 콜백 함수(executor)를 인수로 전달받는데 이 콜백 함수는 resolve, reject 함수를 인수로 전달받는다.Promise 객체가 생성되면 executor는 자동으로 실행되고 작성했던 코드들이 작동.
코드가 정상적으로 처리가 되었다면 resolve 함수를 호출하고 에러가 발생했을 경우에는 reject 함수를 호출하면 된다.
let promise = new Promise((resolve, reject) => {
// 1. 정상적으로 처리되는 경우
// resolve의 인자에 값을 전달할 수도 있습니다.
resolve(value);
// 2. 에러가 발생하는 경우
// reject의 인자에 에러메세지를 전달할 수도 있습니다.
reject(error);
});

Promise 객체의 내부 프로퍼티new Promise가 반환하는 Promise 객체는 state, result 내부 프로퍼티를 갖는다. .then, .catch, .finally의 메서드를 사용해야 접근이 가능.pending(대기)입니다. 비동기 처리를 수행할 콜백 함수(executor)가 성공적으로 작동했다면 fulfilled(이행)로 변경이 되고, 에러가 발생했다면 rejected(거부)가 된다.undefined입니다. 비동기 처리를 수행할 콜백 함수(executor)가 성공적으로 작동하여 resolve(value)가 호출되면 value로, 에러가 발생하여 reject(error)가 호출되면 error로 변한다.then, catch, finallyThenexecutor에 작성했던 코드들이 정상적으로 처리가 되었다면 resolve 함수를 호출하고 .then 메서드로 접근할 수 있다. .then 안에서 리턴한 값이 Promise면 Promise의 내부 프로퍼티 result를 다음 .then 의 콜백 함수의 인자로 받아오고, Promise가 아니라면 리턴한 값을 .then 의 콜백 함수의 인자로 받아올 수 있다. 아래의 .then 과 Promise chaining의 예시를 살펴보면서 동작 방식을 확인해 보자.
let promise = new Promise((resolve, reject) => {
resolve("성공");
});
promise.then(value => {
console.log(value);
// "성공"
})
Catchexecutor에 작성했던 코드들이 에러가 발생했을 경우에는 reject 함수를 호출하고 .catch 메서드로 접근할 수 있다.
let promise = new Promise(function(resolve, reject) {
reject(new Error("에러"))
});
promise.catch(error => {
console.log(error);
// Error: 에러
})
Finallyexecutor에 작성했던 코드들의 정상 처리 여부와 상관없이 .finally 메서드로 접근할 수 있다.
let promise = new Promise(function(resolve, reject) {
resolve("성공");
});
promise
.then(value => {
console.log(value);
// "성공"
})
.catch(error => {
console.log(error);
})
.finally(() => {
console.log("성공이든 실패든 작동!");
// "성공이든 실패든 작동!"
})
Promise chainingPromise chaining가 필요하는 경우는 비동기 작업을 순차적으로 진행해야 하는 경우. Promise chaining이 가능한 이유는 .then, .catch, .finally 의 메서드들은 Promise를 리턴하기 때문. 따라서 .then을 통해 연결할 수 있고, 에러가 발생할 경우 .catch 로 처리하면 된다.
let promise = new Promise(function(resolve, reject) {
resolve('성공');
...
});
promise
.then((value) => {
console.log(value);
return '성공';
})
.then((value) => {
console.log(value);
return '성공';
})
.then((value) => {
console.log(value);
return '성공';
})
.catch((error) => {
console.log(error);
return '실패';
})
.finally(() => {
console.log('성공이든 실패든 작동!');
});
Promise.all()Promise.all()은 여러 개의 비동기 작업을 동시에 처리하고 싶을 때 사용const promiseOne = () => new Promise((resolve, reject) => setTimeout(() => resolve('1초'), 1000));
const promiseTwo = () => new Promise((resolve, reject) => setTimeout(() => resolve('2초'), 2000));
const promiseThree = () => new Promise((resolve, reject) => setTimeout(() => resolve('3초'), 3000));Promise에서 executor 내 작성했던 코드들이 정상적으로 처리가 되었다면 결과를 배열에 저장해 새로운 Promise를 반환.// 기존
const result = [];
promiseOne()
.then(value => {
result.push(value);
return promiseTwo();
})
.then(value => {
result.push(value);
return promiseThree();
})
.then(value => {
result.push(value);
console.log(result);
// ['1초', '2초', '3초']
})Promise.all()을 통해 해결할 수 있습니다. Promise.all()은 비동기 작업들을 동시에 처리.// promise.all
Promise.all([promiseOne(), promiseTwo(), promiseThree()])
.then((value) => console.log(value))
// ['1초', '2초', '3초']
.catch((err) => console.log(err));Promise.all()은 인자로 받는 배열에 있는 Promise 중 하나라도 에러가 발생하게 되면 나머지 Promise의 state와 상관없이 즉시 종료.Error: 에러1이 반환된 후로는 더 이상 작동하지 않고 종료Promise.all([
new Promise((resolve, reject) => setTimeout(() => reject(new Error('에러1'))), 1000),
new Promise((resolve, reject) => setTimeout(() => reject(new Error('에러2'))), 2000),
new Promise((resolve, reject) => setTimeout(() => reject(new Error('에러3'))), 3000),
])
.then((value) => console.log(value))
.catch((err) => console.log(err));
// Error: 에러1Promise HellPromise를 통해 비동기 코드의 순서를 제어할 수 있지만 Callback 함수와 같이 코드가 길어질수록 복잡해지고 가독성이 낮아지는 Promise Hell이 발생하는 단점이 있다.
const printString = (string) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(string);
}, Math.floor(Math.random() * 100) + 1);
});
};
const printAll = () => {
printString('A').then((value) => {
console.log(value);
printString('B').then((value) => {
console.log(value);
printString('C').then((value) => {
console.log(value);
printString('D').then((value) => {
console.log(value);
printString('E').then((value) => {
console.log(value);
printString('F').then((value) => {
console.log(value);
printString('G').then((value) => {
console.log(value);
printString('H').then((value) => {
console.log(value);
printString('I').then((value) => {
console.log(value);
printString('J').then((value) => {
console.log(value);
printString('K').then((value) => {
console.log(value);
printString('L').then((value) => {
console.log(value);
printString('M').then((value) => {
console.log(value);
printString('N').then((value) => {
console.log(value);
printString('O').then((value) => {
console.log(value);
printString('P').then((value) => {
console.log(value);
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
};
printAll();
console.log(
`아래와 같이 Promise를 통해 비동기 코드의 순서를 제어할 수 있지만 Callback 함수와 같이 코드가 길어질수록 복잡해지고 가독성이 낮아지는 Promise Hell이 발생하는 단점이 있습니다.`
);
// 출력 ↓
// 아래와 같이 Promise를 통해 비동기 코드의 순서를 제어할 수 있지만 Callback 함수와 같이 코드가 길어질수록 복잡해지고 가독성이 낮아지는 Promise Hell이 발생하는 단점이 있습니다.
// A
// B
// ...
// O
// P
Async/Awaitasync/await키워드를 제공하였다. Promise 코드를 간결하게 작성할 수 있게 되었다. async 키워드를 사용하고 async 함수 내에서만 await 키워드를 사용하면 됩니다. await 키워드가 작성된 코드가 동작하고 나서야 다음 순서의 코드가 동작하게 된다.// 함수 선언식
async function funcDeclarations() {
await 작성하고자 하는 코드
...
}
// 함수 표현식
const funcExpression = async function () {
await 작성하고자 하는 코드
...
}
// 화살표 함수
const ArrowFunc = async () => {
await 작성하고자 하는 코드
...
}
Node.js브라우저에서 사용할 수 있는 비동기 흐름은 타이머 혹은 DOM 이벤트와 관련된 상황으로 다소 한정적이지만, Node.js의 경우 많은 API가 비동기로 작성되어 있다.
Node.js : 비동기 이벤트 기반 JavaScript 런타임
모듈이란?
- 건축으로부터 비롯된 모듈이라는 단어는, 어떤 기능을 조립할 수 있는 형태로 만든 부분
- 그중
fs(File System) 모듈은, PC의 파일을 읽거나 저장하는 등의 일을 할 수 있게 도와준다.
DNS : 파일 시스템 모듈이 파일을 읽거나 저장하는 기능을 구현할 수 있도록 돕는다.모듈을 사용하기 위해 불러오는 과정이 필요하다.<script> 태그를 이용했다.// HTML에서 JavaScript 파일을 불러오는 script 태그
<script src="불러오고싶은_스크립트.js"></script>require 구문을 이용하여 다른 파일을 불러온다.// Node.js에서 다른 파일을 불러오는 require 구문
const fs = require('fs'); // 파일 시스템 모듈을 불러옵니다
const dns = require('dns'); // DNS 모듈을 불러옵니다예를 들어, Node.js에서 underscore는 Node.js 공식 문서에 없는 모듈이기 때문에 서드 파티 모듈입니다.
underscore와 같은 서드 파티 모듈을 다운로드하기 위해서는 npm을 사용해야 합니다.underscore : 내장 개체를 확장하지 않고 유용한 함수형 프로그래밍 도우미를 제공하는 JavaScript 라이브러리// 터미널에서 다음과 같이 입력해 underscore를 설치할 수 있습니다.
npm install underscore// Node.js의 3rd-party underscore를 사용할 수 있습니다.
const _ = require('underscore');fs.readFile을 통해 알아보는 Node.js 공식문서 가이드fs.readFile은 로컬에 존재하는 파일을 읽어온다.fs.readFile(path[, options], callback)path \<string> | \<Buffer> | \<URL> | \<integer>pathpath에는 파일 이름을 전달인자로 받습니다. <string>)의 타입을 받습니다.// '/etc/passwd' 파일을 불러오는 예제
fs.readFile('/etc/passwd', ..., ...)options \<Object> | \<string>optionsoptions는 넣을 수도 있고, 넣지 않을 수도 있습니다. 대괄호는 선택적 전달인자를 의미한다.options는 문자열 또는 객체 형태로 받을 수 있다.
문자열로 전달할 경우 인코딩을 받는다.
밑의 예제에서는 'utf8'을 두 번째 전달인자로 받는 것을 확인할 수 있다.
// /etc/passwd 파일을 'utf8'을 사용하여 읽습니다.
// 두 번째 전달인자 options에 문자열을 전달한 경우
fs.readFile('/etc/passwd', 'utf8', ...);
// 두 번째 전달인자 options에 객체를 전달한 경우
let options = {
encoding: 'utf8', // utf8 인코딩 방식으로 엽니다
flag: 'r' // 읽기 위해 엽니다
}
// /etc/passwd 파일을 options를 사용하여 읽습니다.
fs.readFile('/etc/passwd', options, ...)
callback \<Function>callbackerr \<Error> | \<AggregateError>data \<string> | \<Buffer>