DOM Element의 이벤트 핸들러
마우스, 키보드 입력
페이지 로딩
타이머
타이머 API
애니메이션 API
서버의 자원 요청 및 응답
fetch API
AJAX(XHR)
어떤 경우에 중첩된 callback이 발생하는지 이해할 수 있다.
callback은 async를 제어하기 위해 사용한다. 아래는
string
을 출력해주는 함수이다.const printString = (string, callback) => { setTimeout(() => { console.log(string) callback() }, Math.floor(Math.random() * 100) + 1 ) }
위 함수를 사용히여 "A", "B", "C"를 출력할 때, 함수를 그냥 나열하여 사용하면 string은 입력 순서가 아닌 랜덤 순서대로 출력된다. 따라서 "A", "B", "C"를 차례로 나열하고 싶을 때에는 아래와 같이 callback함수를 중첩하여 사용해야 한다.
const printAll = () => { printString("A", () => { printString("B", () => { printString("C", () => {}) }) }) } printAll();
중첩된 callback의 단점, Promise의 장점을 이해할 수 있다.
위의 경우 callback 함수가 3개밖에 없기 떄문에 함수를 이해하는 데에 큰 어려움이 없지만, 중첩된 callback함수가 너무 많으면 함수의 가독성이 떨어지고 함수를 관리하기가 어려워진다. 이를
"callback HELL"
이라고 부른다. 이를 해결하기 위해Promise
를 사용한다.Promise
는 코드의 깊이가 평탄해서 callback 패턴에 비해 유지보수에 용이하다. 또 다른 비동기 작업을 쉽게 추가하거나 수정할 수 있다.
Promise 사용 패턴을 이해할 수 있다.
Promise
는 함수를 만들 때 callback이 아닌,resolve
와reject
함수를 인자로 받으며,new Promise
를 리턴한다.▶
resolve
와reject
resolve 와 reject 는 함수로서 호출되면 promise 를 이행하거나 거부한다. 이 둘을 이용하여 비동기 작업이 모두 끝나면 resolve 를 호출해 이행하고, 중간에 오류가 생기면 reject 를 이용해 거부한다.▶
then
과catch
const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve("resolve") }, Math.floor(Math.random() * 100) + 1 ) } promise.then((result) => console.log(result));
위의 경우 promise가 종료되면 resolve 값을 then으로 받는다. 하지만 reject의 경우는 then으로 받을 수 가 없다. 그럴 때 catch를 사용한다.
const promise = new Promise((resolve, reject) => { setTimeout(() => { reject("reject") }, Math.floor(Math.random() * 100) + 1 ) }) promise.then((result) => console.log(result)).catch((err) => console.log(err));
then
과catch
는 절대 같이 실행될 수 없다. 무조건resolve
시에then
,reject
시에catch
가 실행된다.
Promise의 세 가지 상태를 이해할 수 있다.
pedding(대기)
: resolve 할지 reject 할 지 결정되지 않은 초기의 상태이다.
fullfilled(이행)
: 연산이 성공한 상태이다.
rejected(거부)
: 연산이 실패한 상태이다.
Promise.all 의 사용법을 이해할 수 있다.
Promise.all
은 주어진 모든 Promise 를 실행한 후 진행되는 하나의 Promise를 배열로 반환한다. 사용법은 아래와 같다.const promise1 = Promise.resolve(3); const promise2 = 42; const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'foo'); }); Promise.all([promise1, promise2, promise3]).then((values) => { console.log(values); });
async/await keyword에 대해 이해하고, 작동 원리를 이해할 수 있다.
async await을 사용하면 비동기 함수를 동기적인 것 처럼 사용할 수 있다. 이는 코드의 가독성을 높여준다. 아래는 async await의 기본 문법이다
async function 함수명() { await 비동기_처리_메서드_명(); }
async가 붙은 함수는 반드시 Promise를 반환하고, Promise가 아닌 것은 Promise로 감싸 반환한다. async 함수 안에서 await 키워드를 만나면 Promise가 처리될 때까지 기다리고, 결과는 그 이후에 반환된다. 기다리는 동안엔 엔진이 다른 일을 할 수 있기 때문에, CPU 리소스가 낭비되지 않는다. 아래는 간단한 예제이다.
const gotoSchool = () => {} const takeClass = () => {} const eatLunch = () => {} const goHome = () => {} const dailyRoutine = async() => { const one = await gotoSchool(); console.log(one); const two = await takeClass(); console.log(two); const three = await eatLunch(); console.log(three); const four = await goHome(); console.log(four);
Node.js의 fs 모듈의 사용법을 이해할 수 있다.
Node.js는 비동기 이벤트 기반의 자바스크립트 런타임이다. 따라서 비동기 흐름이 타이머, DOM 이벤트로 한정되어있는 브라우저에서와 다르게 Node.js에는 많은 API가 비동기로 작성되어있다.
fs module
(= File System module) 이란, 파일 처리와 관련된 전반적인 작업을 하는 모듈을 말한다. 사용하기 위해서는 코드의 최상단에require
구문을 이용하여 파일을 불러와야 한다.const fs = require('fs')
▶ fs.readFile(path[,options], callback)
: 인자 세 개를 받아 비동기적으로 파일 내용 전체를 읽는다.
path\<string>|\<Buffer>|\<URL>|\<integer>
: 파일 이름 => 4가지 타입. 일반적으로 string 타입이다.options\<Object>|\<string>
: 선택적 인자 => 객체 또는 문자열(encoding)callback\<Function>
: 파일을 일고난 후 비동기적으로 실행되는 함수
err\<Error>
: 에러 발생 안하면 null
data\<string>|\<Buffer>
: 파일의 내용 => 문자열 또는 버퍼(encoding 없을 시)const getDataFromFile = function (filePath, callback) { fs.readFile(filePath, "utf-8", (err, data) => { if(err) { return callback(err, null); } else { return callback(null, data); } }) }