일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- ...args
- .toLocalString()
- 1주차
- 2020년 준비
- 2주차
- 4주차
- 5주차
- array
- array method
- async
- authentication
- AWS
- codestates
- commit
- Cookie
- CSS
- Data Structre
- Data Structure
- DataSturcutre
- Date.now()
- DB에 사진 저장하기
- Dev log
- DOM
- EC2
- EC2로 웹 만드는 방법
- EC2와 S3 연결하기
- element
- Es5
- ES6
- event 객체
- Today
- Total
souvenir
20.08.10_Async & Callback & Promise 본문
나는 미친듯이 멀티태스킹이 안되는 사람이다.
그래서 학교 다닐 때 자신이 좋아하는 노래를 들으면서 공부하는 친구들을 보면 그렇게 부럽고 대단하였다. 물론 시간이 지나 연습해보면서 어느정도의 멀티 태스킹이 가능하게 되었지만 여전히 쉽지 않다... (강제로 모든 것에 올인해야함)
Why Async?
갑자기 멀티테스킹을 이야기 하는 이유는 내가 공부하고 있는 JavaScript라는 언어도 멀티태스킹이 안되는 언어이기 때문이다. call Stack에 함수를 쌓아서 stack의 순서대로 함수를 실행하는, C나 다른 언어들에 비하면 참으로 심플한 언어이다. 문제는 JS가 주로 웹에서 사용된다는 것이다. 이렇게 한번에 하나의 일만 하게 되면 어떻게 될까?
극적인 예시로 유튜브에서 영상을 보기위해 영상을 클릭했다고 하자.
영상은 예상하겠지만 꽤나 용량이 크기 때문에 로딩 시간이 길 것이다. 그런데 로딩되는 동안, 다른 추천 영상을 클릭하는 것도 좋아요 버튼도 댓글 추가도 할 수 없다면 어떻게 될까? 성격급한 한국인 특성상 답답해서 창을 아예 닫아버릴지도 모른다. 이런 상황을 '동기적(Synchronous)'으로 운영된다고 말한다.
반대로 영상이 로딩 되는 동안에 다른 task들도 진행할 수 있는 방식을 '비동기적(Asybchronous)'으로 운영된다고 말한다.
-
Asybchronous : 비동기적인. 작업이 진행중일 동안 다른 작업도 진행할 수 있기 때문에 전체 작업 시간이 많이 짧아짐. 즉 이전 작업이 blocking 하지 않기 때문임. (non-blocking) 실생활 웹에서도 많이 사용함.
-
Synchronous : 동기적인. 각각의 작업 소요시간을 합친 것이 전체 작업 소요 시간.
그런데 분면 JS는 동기적으로 운영되는 언어라고 하였는데 실제 JS를 사용한 웹에서도 동기적으로 운영되는 것 같은 모습을 보인다.
그 이유는 JS에서 callback이나 WebAPI 혹은 Promise 등을 통해 비동기적인 방식을 구현해 내기 때문이다.
Callback
그러나 비동기으로 했을 때의 단점이 있다. 그것은 순서를 예상하기 어렵다는 것이다. 각각의 작업 소요시간이 다르기 때문에 내가 원하는대로가 아닌 작업이 빨리 끝난 순대로 실행될 수 있기 때문이다.
예를 들면 아래와 같다.
const printString = (stirng) => {
setTimeout(
() => {
console.log(string)
},
Math.floor(Math.random() * 100) + 1
)
}
const printAll = () =>
printString("A")
printString("B")
printString("C")
}
printAll() //A, B, C가 랜덤하게 출력됨
그렇다면 어떻게 순서를 제어할 수 있을까?
가장 단순한 방법은 CALLBACK을 활용하는 것이다.
ex) 너가 작업이 얼마나 끝날지 모르겠지만 끝나면 나 다시 불러줘
const printString = (stirng, callback) => {
setTimeout(
() => {
console.log(string),
callback()
},
Math.floor(Math.random() * 100) + 1
)
}
const printAll = () => {
printString("A", () => { //callback
printString("B"), () => { //callback
printString("C"), () => {})
})
})
}
}
printAll() //A, B, C가 순서대로 출력됨
위 함수의 경우 callback을 통해 다음 함수를 호출해 주고 있음. 그렇기 때문에 순서대로 실행할 수 있도록 해준다.
이 외에도 사용자에게 err 메세지를 제시하는데도 활용할 수 있다.
아래는 callback 함수에 인자가 있는 경우이다.
아래와 같은 흐름으로 작성해 볼 수 있다.
const somethingGonnaHappen = callback => {
waitngUntillSomethingHappens()
if(isSomethingGood) {
callback(null, something)
}
if(isSomethingBad) {
callback(something, null)
}
}
실제 사용 예시
somethingGonnaHappen((err, data) => {
if(err) {
console.log('ERR!!');
return;
}
return data;
})
Promise
그러나 콜백을 무한정 쓰게 되면 콜백 헬에 빠지게 된다.
콜백 헬을 벗어나 callback chain을 관리하기 위해 Promise()를 통해 callback으로 구현한 것을 그대로 만들 수 있다.
primes() 자체가 하나의 class와 같기에 new Promise() 등으로 할당할 수 있다. 파라미터로는 resolve(), reject() 두가지 함수가 들어갈 수 있다.(당연히 함수의 이름은 유동적으로 바꿀 수 있다.)
Callback → Priomise
const printString = (stirng) => {
return new Promise((resolve, reject) => {
setTimeout(
() => {
console.log(string),
resolve() //이 함수에서는 따로 에러를 잡을 필요가 없기에 reject()는 넣지 않음
},
Math.floor(Math.random() * 100) + 1
)
})
}
const printAll = () => {
printString("A")
.then() => {
return printString("B") //return을 통해 다음 함수를 호출(promise chaining)
})
.then(() => {
return printString("C")
})
//만약 reject가 있었다면 여기에 .catch()가 있었을 것
}
}
printAll() //A, B, C가 순서대로 출력됨
즉 .then()을 통해 순서 연결을 할 수 있음. .catch()를 통해 어디서 에러가 나더라도 에러를 잡아낼 수 있음.
4. async await
: 노드 버전이 높으면 사용할 수 있음.
promise인데 작성방법이 조금 다름. await를 써서 마치 동기적인 것처럼 사용할 수 있음.
promise chaining과 유사하지만 가독성이 조금 더 높다는 의미가 있음. 또한 await를 사용하면 .then도 포함된 의미로 사용할 수 있다.
예시)
function gotoCodestates() {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve('1. go to codestates') },
Math.floor(Math.random() * 500) + 1)
})
}
function sitAndCode() {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve('2. sit and code') },
Math.floor(Math.random() * 400) + 1)
})
}
function eatLunch() {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve('3. eat lunch') },
Math.floor(Math.random() * 300) + 1)
})
}
function goToBed() {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve('4. goToBed') },
Math.floor(Math.random() * 200) + 1)
})
}
const result = async () => { //async()로 먼저 선언을 해주어야 함.
const one = await gotoCodestates(); //gotoCodestates()이 실행이 끝난 후 다음이 실행.
console.log(one)
const two = await sitAndCode();
console.log(two)
const three = await eatLunch();
console.log(three)
const four = await goToBed();
console.log(four)
}
result(); //goToBed()가 아닌, 위 순서대로 출력함.
참고링크)
Promises chaining : https://javascript.info/promise-chaining
Async/await : https://javascript.info/async-await
Primise : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
'2020년 > TIL(Today I Learn)' 카테고리의 다른 글
20.09.09_Authentication(인증) (0) | 2020.09.17 |
---|---|
20.08.10 TIL_node.js module 사용 (0) | 2020.08.11 |
20.08.03 Time Complex 정리 (0) | 2020.08.11 |
20.07.28_문제 오답 노트 (0) | 2020.07.28 |
Linked List(연결리스트) 의 개념과 구현 (2) | 2020.07.27 |