자바스크립트는 동기식 언어로 한 번에 하나의 작업을 수행한다.
동기란? 프로그램이 작성된 순서대로 실행되는 것
비동기란? 특정코드가 끝날 때까지 기다렸다가 다음 코드를 진행하는 것이 아닌
코드의 진행이 멈추지 않고 다음 코드를 먼저 실행하는 것이다.
- 동기
-- 직렬적(순서대로)으로 작업을 수행한다.
즉, 요청을 보낸 후 응답을 받아야만 다음동작이 이루어지는 방식이다.
어떠한 작업을 처리할 동안 다음의 나머지 작업들은 대기한다.- 비동기
-- 요청을 보낸 후 응답의 수락 여부와는 상관없이 다음 작업이 동작하는 방식이다.
a작업을 실행하는 시간동안 b작업을 할 수 있으므로 자원을 효율적으로 사용할 수 있다.
콜백함수란? 함수 자체를 인자로 전달하는 방식으로 함수 안에서 실행되는 또 다른 함수이다.
즉, 파라미터로 변수가 아닌 함수를 전달하는 것을 말한다.
보통 함수를 선언한 뒤에 함수 타입 파라미터를 맨 마지막에 하나 더 선언해 주는 방식으로 정의한다.
처리가 끝나면 파라미터로 전달 받은 함수를 실행한다.
function mainFunc(param1, param2, callbackFunc) {
// ... 처리 내용 작성
callbackFunc(result);
}
콜백함수의 대표적인 사용 예로는 setTimeout함수가 있다.
브라우저에 요청을 보냈던 것이 처리가 되면 이를 실행할 수 있도록 나중에 다시 불러야 하는데, 이 불러달라는 것에 착안하여 Call Back 함수라고 이름이 붙었다.
console.log('1');
setTimeout(function(){
console.log('2');
},1000);
console.log('3');
1->3->2의 순서로 실행된다.
콜백함수를 남용하면 코드의 깊이가 깊어지며 가독성이 떨어지고 오류를 찾기도 어려워질 수 있다.
const obj = {
loginUser : function(id, password, onSuccess, onError){
setTimeout(()=>{
if (
(id === 'joy' && password === 'joyy') ||
(id === 'yeon' && password === 'yeonn')
) {
onSuccess(id)
}
else {
onError(new Error('not Found'))
}
},2000)
},
getRoles : function(id, onSuccess, onError){
setTimeout(() => {
if (id === 'joy') {
onSuccess({ name: 'joy', role: 'admin' })
} else {
onError(new Error('No Access'))
}
}, 1000)
}
}
// 구현할 프로세스
// 1. 사용자에게 id, password 입력받기
// 2. 로그인
// 3. 로그인 성공 시 받아온 id로 role 받아오기
// 4. 성공적으로 role을 받아오면 name과 role 출력
let id = prompt("id를 입력해주세요.");
let password = prompt("password를 입력해주세요.");
obj.loginUser(
id,
password,
// loginUser 메소드의 onSuccess 콜백함수 전달 === getRoles함수 호출
(id) => {
obj.getRoles(
id,
// getRoles 메소드의 onSuccess 콜백함수 전달
(userWithRole) => {
alert(
`Hello ${userWithRole.name}! you have a ${userWithRole.role} role. `
);
},
// getRoles 메소드의 onError 콜백함수 전달
(error) => {
console.log("no access");
}
);
},
// loginUser 메소드의 onError 콜백함수 전달
(error) => {
console.log("error");
}
);
obj객체에서 id, password 를 받아온다.
입력을 받아와 로그인에 성공하면 onSucccess(id) 를 통해 Roles, 역할을 요청하게 된다. (getRoles)
역할을 받아 올 수 있다면, 사용자의 객체(이름, 역할이 들어있는)를 보이게 한다.
이런 콜백지옥을 해결하기 위해 Promise나 async/await를 사용할 수 있다.
ES6에서는 비동기 처리를 위한 또 다른 패턴으로 Promise를 도입했다.
Promise 는 자바스크립트에서 제공하는 비동기를 간편하게 처리할 수 있게 도와주는 객체이다.
작업 결과 따라 성공 또는 실패를 리턴하며 결과 값을 전달 받을 수 있다.
Promise는 비동기 작업을 수행 할 콜백함수를 인자로 전달 받는다.(resolve(성공), reject(실패))
const 변수명 = new Promise((resolve,reject) => {
// resolve('');
// reject('');
});
Promise 객체는 state(상태)와 result(결과)를 프로퍼티로 갖는다.
Promise의 3가지 상태
Pending -> fulfilled가 되면 result는 resolve(value) 즉, resolve함수로 전달된 값이 된다.
Pending -> rejected가 되면 result는 reject(error) 즉, reject 함수로 전달된 error가된다.
promise의 상태가 fulfilled가 되면 then()을 이용하여 처리 결과 값을 받을 수 있고, rejected가 되면 catch()로 실패한 처리 결과 값을 받을 수 있다.
const 변수명 = new Promise( (resolve, reject) => {
setTimeout(() => {
resolve('OK')
},1000)
});
변수명.then((value) => {
console.log(value);
});
promise는 callback 패턴과는 다르게, 에러 상태를 관리함으로써 에러 처리가 가능해졌다.
const promise1 = new Promise( (resolve, reject) => {
setTimeout(() => {
if('1' == '1'){
resolve('ok');
} else{
reject('error');
}
},1000)
});
promise1.then((value) => {
console.log(value);
});
promise1.catch((value) => {
console.log(value);
});
조건문이 '참'이 되면 resolve로 then()이 실행되고,
그렇지 않으면 catch()가 실행된다.
프로미스는 후속 처리 메서드를 체이닝 하여 여러 개의 프로미스를 연결하여 사용할 수 있다.
const promise1 = () => new Promise((resolve, reject) => {
setTimeout(() => {resolve("🥚")},1000)
});
const promise2 = (step1) => new Promise((resolve, reject) => {
setTimeout(() => {resolve(`${step1} -> 🐣`)},1000)
});
const promise3 = (step2) => new Promise((resolve, reject) => {
setTimeout(() => {resolve(`${step2} -> 🐥`)},1000)
});
promise1() //
.then((step1) => promise2(step1))
.then((step2) => promise3(step2))
.then((result) => console.log(result))
// 🥚 -> 🐣 -> 🐥