솔미는 성장중
[JS] 동기/비동기 (콜백 패턴, promise, Async & Await, Resolve, Reject, 에러 핸들링, 반복문에서의 비동기) 본문
[JS] 동기/비동기 (콜백 패턴, promise, Async & Await, Resolve, Reject, 에러 핸들링, 반복문에서의 비동기)
solming 2023. 7. 31. 17:49개념
동기 : 작업을 동시에 수행하거나, 동시에 끝나거나, 끝나는 동시에 시작
비동기 : 시작, 종료가 일치하지 않으며, 끝나는 동시에 시작을 하지 않음
콜백 패턴
예시) 비동기로 작동하는 a함수를 콜백 함수를 통해 a,b순으로 실행되게 만들기
const a = (callback)=>{
setTimeout(()=>{
console.log(1)
callback()
},1000)
}
const b = () => console.log(2)
// a(()=>{})
a(()=>{
b()
})
//1
//2
예시) b함수도 a함수처럼 비동기로 작동하게
const a = (callback)=>{
setTimeout(()=>{
console.log(1)
callback()
},1000)
}
const b = ()=>{
setTimeout(()=>{
console.log(2)
},1000)
}
const c = () => console.log(3)
a(()=>{
b()
})
c()
//3
//1
//2
예시) a, b 함수가 비동기로 작동할 때 a,b,c 함수 순으로 실행되게 하고 싶다면?
const a = (callback)=>{
setTimeout(()=>{
console.log(1)
callback()
},1000)
}
const b = (callback)=>{
setTimeout(()=>{
console.log(2)
callback()
},1000)
}
const c = () => console.log(3)
a(()=>{
b(()=>{
c()
})
})
//1
//2
//3
이런 식으로 개수가 점점 늘어난다면 개미지옥 형태처럼 생기게 된다.
이것이 바로 콜백지옥!
a(()=>{
b(()=>{
c(()=>{
d()
})
})
})
읽거나 관리하기 불편하기 때문에 대체하기 위해 만들어진 것이 Promise 클래스!
Promise 클래스
앞서 콜백 함수를 설명할 때 썼던 예시와 동일한 예시를 사용한다.
예시) a,b함수 순차적으로 작동하게 만들기 (Promise 클래스를 사용해 변형해준 것.)
const a = ()=>{
return new Promise(resolve =>{ //생성자함수
setTimeout(()=>{
console.log(1)
resolve()
},1000)
})
}
const b = () => console.log(2)
a().then(()=>{b()}) //then은 resolve매개변수로 들어감
//1
//2
예시) a,b,c,d함수가 있을 때 비동기 코드를 순차적으로 작동하게 만들기
const a = ()=>{
return new Promise(resolve =>{ //생성자함수
setTimeout(()=>{
console.log(1)
resolve()
},1000)
})
}
const b = ()=>{
return new Promise(resolve =>{ //생성자함수
setTimeout(()=>{
console.log(2)
resolve()
},1000)
})
}
const c = ()=>{
return new Promise(resolve =>{ //생성자함수
setTimeout(()=>{
console.log(3)
resolve()
},1000)
})
}
const d = ()=>console.log(4)
a().then(()=>{ //a의 resolve로 들어간다.
return b() //return new Promise를 통해 return
}).then(()=>{ //b의 resolve로 들어간다.
return c()
}).then(()=>{
d()
})
//1,2,3,4
//아래 처럼 정리도 가능. 1
a()
.then(()=>b())
.then(()=>c())
.then(()=>{
d()
})
//1,2,3,4
//아래 처럼 정리도 가능. 2
a()
.then(b)
.then(c) //c라는 함수가 b함수 resolve매개변수 자리로 들어가 콘솔2 출력, resolve실행.
.then(d)
.then(()=>console.log('done')
//1,2,3,4,done
다른 예시)
Async & Await
예시) await함수를 써서 a,b함수가 순차적으로 작동하게 만들기
const a = ()=>{
return new Promise(resolve =>{ //생성자함수
setTimeout(()=>{
console.log(1)
resolve()
},1000)
})
}
const b = () => console.log(2)
const wrap = async { // await키워드는 async키워드가 붙은 함수로 감싸야 한다.
await a() // 비동기코드로 만들어진 a함수에서 resolve()까지 실행할 때까지 기다렸다가
b() // b 호출
}
wrap()
//1
//2
- await는 Promise instance가 반환되어야만 사용할 수 있다.
- await키워드는 async키워드가 붙은 함수로 감싸야 한다.
다른 예시)
Promise 생성자 콜백에서 사용할 수 있는
Resolve, Reject, 에러 핸들링
예제코드1)
Promise를 사용해서 resolve 상황, reject 상황 코드 구현하기
const delayAdd = index => {
return new Promise((resolve, reject) => {
setTimeout(()=>{
if(index>10){ //10보다 큰 숫자가 들어오면 에러 실행
reject('${index}는 10보다 커서 안된다.')
return //reject가 실행되면 resolve는 실행되지 않지만 console.log는 실행될 수 있기에 return
}
console.log(index)
resolve(index+1) //정상 작동하면 여기 실행
},1000)
})
}
//1번째 방법: then 키워드 사용하기
delayAdd(12)
.then(res=>console.log(res))
.catch(err=>console.error(err)) //catch메소드를 사용하면 reject 매개변수로 들어감
//12는 10보다 커서 안된다.
//2번째 방법: await 사용하기
const wrap = async () => {
try{
const res = await delayAdd(12) //10보다 큰 수를 넣어서 에러 발생
console.log(res) //try catch 구문에서는 에러가 발생하면 그 코드를 제외하고 나머지는 동작 X
} catch (err) {
console.error(err)
} finally {
console.log('Done!')
}
}
wrap()
//12는 10보다 커서 안된다.
//Done!
- reject가 실행되면 resolve는 실행되지 않지만 console.log는 실행될 수 있기에 return
- try catch 구문에서는 에러가 발생하면 그 코드를 제외하고 나머지는 동작 X
- finally를 사용한 부분은 error여부에 관계없이 무조건 실행
예제코드2)
- resolve함수가 동작하면 reject와 catch모두 동작하지 않는다.
- 주소를 잘못 입력해 불러올 수 없게 된다면 '에러 발생 : ~' 내용이 뜨게 된다.
- catch메소드로 걸러지지 않는 실질적인 에러를 확인하기 위해서 정상 작동을 의미한 then메소드 내에 작성
위 예시 await써서 수정하기)
반복문에서 비동기 처리
forEach
- 사용하면 안된다.
- await를 사용해도 순서를 보장하지 않음. 왜냐하면 기다렸다가 다음 콜백으로 넘어가는 게 아니기 때문.
- 콜백이 반복될 때 바로바로 실행된다고 봐야 함.
(아래 사진에서 주석처리된 부분에 해당된다.
이 부분을 실행하면 frozen, avengers, avatar 순서가 실행할 때 마다 바뀐다.)
for 반복문을 사용하자
'JavaScript' 카테고리의 다른 글
[JS] 불변성 (0) | 2023.07.31 |
---|---|
[JS] DOM (0) | 2023.07.31 |
[JS] fetch() (0) | 2023.07.31 |
[JS] 모듈 (0) | 2023.07.23 |
[JS] prototype + 배열 만드는 방법 (1) | 2023.07.19 |