현재 실행 중인 코드가 완료 된 후에야 다음 코드를 실행하는 방식
CPU의 계산에 의해 즉시 처리가 가능한 대부분의 코드
현재 실행 중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어감
setTimeout(function (name) {
let coffeeList = name;
console.log(coffeeList); // "에스프레소"
setTimeout(function (name) {
coffeeList += ', ' + name;
console.log(coffeeList); // "에스프레소, 아메리카노"
setTimeout(function (name) {
coffeeList += ', ' + name;
console.log(coffeeList); // "에스프레소, 아메리카노, 카페모카"
setTimeout(function (name) {
coffeeList += ', ' + name;
console.log(coffeeList); // "에스프레소, 아메리카노, 카페모카, 카페라떼"
}, 500, '카페라떼');
}, 500, '카페모카');
}, 500, '아메리카노');
}, 500, '에스프레소');
목적 달성에는 지장이 없지만 들여쓰기 수준이 과도하게 깊어짐
값이 전달되는 순서가 '아래에서 위로' 향하고 있어 어색하게 느껴짐
let coffeeList = '';
const addEspresso = function (name) {
coffeeList = name;
console.log(coffeeList); // "에스프레소"
setTimeout(addAmericano, 500, '아메리카노');
};
const addAmericano = function (name) {
coffeeList += ', ' + name;
console.log(coffeeList); // "에스프레소, 아메리카노"
setTimeout(addMocha, 500, '카페모카');
};
const addMocha = function (name) {
coffeeList += ', ' + name;
console.log(coffeeList); // "에스프레소, 아메리카노, 카페모카"
setTimeout(addLatte, 500, '카페라떼');
};
const addLatte = function (name) {
coffeeList += ', ' + name;
console.log(coffeeList); // "에스프레소, 아메리카노, 카페모카, 카페라떼"
};
setTimeout(addEspresso, 500, '에스프레소');
코드의 가독성을 높임
함수 선언과 함수 호출만 구분할 수 있다면 위에서부터 아래로 순서대로 읽어 내려가는데 어려움이 없음
ES6(ES2015)에서 Promise, Generator 등이 도입
ES8(ES2017)에서 async / await 이 도입
new Promise(function (resolve) {
setTimeout(function () {
const name = '에스프레소';
console.log(name);
resolve(name);
}, 500);
}).then(function (prevName) {
return new Promise(function (resolve) {
setTimeout(function () {
const name = prevName + ', 아메리카노';
console.log(name);
resolve(name);
}, 500);
});
}).then(function (prevName) {
return new Promise(function (resolve) {
setTimeout(function () {
const name = prevName + ', 카페모카';
console.log(name);
resolve(name);
}, 500);
});
}).then(function (prevName) {
return new Promise(function (resolve) {
setTimeout(function () {
const name = prevName + ', 카페라떼';
console.log(name);
resolve(name);
}, 500);
});
})
new 연산자와 함께 호출한 Promise의 인자로 넘겨주는 콜백 함수는 호출할 때 바로 실행
그 내부에 resolve 또는 reject 함수를 호출하는 구문이 있을 경우 둘 중 하나가 실행되기 전까지는 then 또는 catch 로 넘어가지 않음
const addCoffee = function (name) {
return function (prevName) {
return new Promise(function (resolve) {
setTimeout(function () {
const newName = prevName ? (prevName + ', ' + name) : name;
console.log(newName);
resolve(newName);
}, 500);
});
}
};
addCoffee('에스프레소')()
.then(addCoffee('아메리카노'))
.then(addCoffee('카페모카'))
.then(addCoffee('카페라떼'))
반복적인 내용을 함수화해서 더욱 짧게 표현
const addCoffee = function (prevName, name) {
setTimeout(function () {
coffeeMaker.next(prevName ? prevName + ', ' + name : name);
}, 500);
};
const coffeeGenerator = function* () {
const espresso = yield addCoffee('', '에스프레소');
console.log(espresso);
const americano = yield addCoffee(espresso, '아메리카노');
console.log(americano);
const mocha = yield addCoffee(americano, '카페모카');
console.log(mocha);
const latte = yield addCoffee(mocha, '카페라떼');
console.log(latte);
};
const coffeeMaker = coffeeGenerator();
coffeeMaker.next();
ES6의 Generator를 이용
'*'이 붙은 함수가 Generator
Generator 함수를 실행하면 Iterator가 반환되고, Iterator는 next라는 메서드를 가지고 있음
next 메서드를 호출하면 Generator 함수 내부에서 가장 먼저 등장하는 yield에서 함수의 실행을 멈춤
이후 다시 next 메서드를 호출하면 앞서 멈췄던 부분부터 시작해서 그 다음에 등장하는 yield에서 함수의 실행을 멈춤
비동기 작업이 완료되는 시점마다 next 메서드를 호출하면 Generator 함수 내부의 소스가 위에서부터 아래로 순차적으로 진행 됨
const addCoffee = function (name) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(name);
}, 500);
});
};
const coffeeMaker = async function () {
let coffeeList = '';
const _addCoffee = async function (name) {
coffeeList += (coffeeList ? ',' : '') + await addCoffee(name);
};
await _addCoffee('에스프레소');
console.log(coffeeList);
await _addCoffee('아메리카노');
console.log(coffeeList);
await _addCoffee('카페모카');
console.log(coffeeList);
await _addCoffee('카페라떼');
console.log(coffeeList);
};
coffeeMaker();
ES8(ES2017)에서 가독성이 뛰어나면서 작성법도 간단한 새로운 기능이 추가
비동기 작업을 수행하고자 하는 함수 앞에 async 표기, 함수 내부에서 실질적인 비동기 작업이 필요한 위치마다 await 표기
await 뒤의 내용이 Promise로 자동 전환, 해당 내용이 resolve 된 이후에야 다음으로 진행