동기(synchronous) vs 비동기(asynchronous)
동기(synchronous) | 비동기(asynchronous) | |
예시 | 1.손님1이 아메리카노 주문 (손님2 기다리는중) 2.아메리카노 완성 및 손님1에게 전달(손님2 기다리는중) 3.손님2가 카페라떼 주문 4.손님 카페라떼 완성 및 손님2에게 전달 |
1.손님1이 아메리카노 주문 1-1.아메리카노 만들기 (손님2 주문 받는 중) 1-2.아메리카노 완성되면 손님에게 전달 2.손님2가 카페라떼 주문(손님1 아메리카노 만드는 중) 2-1.카페라떼 만들기 2-2.카페라떼 완성되면 손님에게 전달 |
특징 | 어떤 일을 수행하는 동안 다른 것은 수행 못한다.(blocking) 비유하자면 전화같은 것 |
어떤 일을 수행하면서 다른 일을 수행할 수 있다.(non-blocking) 비유하자면문자같은 것 |
정의 | 요청에 대한 결과가 동시에 일어난다. | 요청에 대한 결과가 동시에 일어나지 않는다. |
사례 | -DOM Element의 이벤트 핸들러 -타이머(setTimeout, requestAnimationFrame등) -서버의 자원 요청 및 응답(fetchAPI,AJAX(XHR)) |
|
이벤트 루프 참고링크1 이벤트 루프 참고링크2 |
비동기 함수 전달 패턴
비동기 함수에서는 동기 함수처럼 한 함수들이 순차적으로 수행되는 것이 아니고,
각각의 함수 수행에 걸리는 시간도 다 다르기 때문에 뭐가 먼저 끝날지 알 수가 없다.
그런데, 비동기적으로 실행되더라도 어떤 부분들은
뭔가가 수행되고 난 다음에 수행되야만 하는 경우도 있다.
이때는 따로 지정해줘야한다.
그런 것들을 지정하는 방식, 패턴에는 아래의 두가지가 있다.
1.callback패턴
let request = 'caffeLatte';
orderCoggeeAsync(request,function(response){
drink(response);
})
2.이벤트 등록 패턴
let request = 'caffelatte';
orderCoffeeAsync(request).onready = function(response){
drink(response)
}
콜백의 예
반복실행하는 함수(iterator)
[1,2,3].map(function(element, index){
return element * element
})
이벤트에 따른 함수(event handler)
document.querySeletor('#btn').addEventListener('click',function(e){
console.log('button clicked')
})
콜백에서 주의
함수의 실행을 연결❌
함수 자체를 연결⭕️
function handleClick(){
console.log('button clicked')
}
//⭕️
document.querySelector('#btn').onclick = handleClick;
//⭕️
document.querySelector('#btn').onclick = function(){
handleClick();
}
//⭕️
document.querySelector('#btn').onclick = handleClick.bind();
//❌
document.querySelector('#btn').onclick = handleClick();
콜백 함수 어떻게 하면 더 효율적으로 부를까
1. callback HELL : 함수안에 함수안에 또 함수안에 함수 넣기
이렇게 하면 너무 코드가 장황하고 이해하기도 힘들다
const printString = (string,callback) => {
setTimeout(
() => {
console.log(string)
callback()
},
Math.floor(Math.random()*100) + 1
)
}
const printAll = () => {
printString("A",()=>{
//함수 안에 콜백함수
printString("B",()=>{
//또 그 콜백함수의 콜백함수
printString("C",()=>{
//또또 그 콜백함수의 콜백함수
})
})
})
}
printAll()
2. Promise : 콜백 체인을 다루기 위한 방법
promise는 비동기 작업의 최종 완료 또는 실패를 나타내는 객체이다.
promise에 대한 내용은 아래의 더보기 버튼 클릭!
👇🏻👇🏻👇🏻
아래의 내용은 유튜브 "코딩앙마"님의 <자바스크립트 중급 강좌 #16 프로미스(Promise)>를 보고,
생각안날때 보려고 만든 자료입니다!
const pr = new Promise((resolve,reject)=>{
//code
})
//resolve와 reject는 모두 콜백 함수이며,
//resolve는 성공했을 때,
//reject는 실패했을 때 실행된다.

위 도식을 코드로 살펴보면 아래와 같다.
resolve와 reject의 상황을 각각 만들어보면 다음과 같다.



이제 소비자의 입장에서 보면 pr.then을 사용해 pr이란 prmise객체를 거쳐서 나온 결과값이 성공인지 실패인지에 따라 then으로 반응할 수 있다. 이때 then안의 콜백두개는 각각 성공시와 실패시의 콜백이며, 안에 들어가는 인자는 pr에서 나온 값이 된다.
위 경우에선 resolve되는 경우이므로 OK가 result로 들어가게 된다.
.then(resolve시콜백, reject시 콜백) => .then(function(result){}, function(err){}) 이런식으로 적는 방법보다 가독성 좋게 적는 방법이 있는데, 그게바로 catch이다.

.then(resolve시콜백).catch(reject시 콜백) => .then(function(result){}).catch(function(err){})
성공시(resolve) 콜백을 then안에 적고, 연결시켜서 실패의 경우(reject)튕겨져나간 실패의 결과값을 catch로 잡아준다.
한눈에 어디가 성공코드고, 어디가 실패코드인지 알 수 있어 보기 좋다.
then과 catch말고 쓸 수 있는게 또 있는데 바로 finally이다.
finally는 이행이든 거부든 처리가 완료되면 항상 실행된다. 따라서 로딩화면 같은 것을 없앨때 유용하게 쓸 수 있다.

직접 코드를 작성하며 테스트해보면 이해가 빠르다.
const pr = new Promise((resolve,reject)=>{
setTimeout(()=>{
// resolve('OK')
reject(new Error('error....'))
},1000)
})
console.log('시작')
pr.then(result => {
console.log(result)
}).catch(err => {
console.log(err)
}).finally(()=>{
console.log("끝")
})
👆🏻👆🏻👆🏻
const printString = (string) => {
//함수 자체를 받을 떄 callback함수를 받을 필요가 없다.
//대신 새로운 Promise객체를 만들어준다.
return new Promise((resolve,reject)=>{
//이 Promise는 자신만의 (resolve와 reject을 인자로 받는) 콜백을 받는다.
//resolve === 함수
//에러 핸들링까지 해주려면 reject사용
setTimeout(
() => {
console.log(string)
resolve()
},
Math.floor(Math.random()*100) + 1
)
})
}
const printAll = () => {
printString("A")
.then(()=>{
return printString("B")
})
.then(()=>{
return printString("C")
})
//reject가 작성된경우 .catch사용가능
}
printAll()
이 promise를 활용한 방법에서 return 처리를 제대로 해주지 않으면(promise chainning을 적절히 사용하지 않으면) 아래와 같이 promise hell에 빠질 수 있다.
promise hell 상황을 보려면 아래의 더보기 클릭!
👇🏻👇🏻👇🏻
function gotoWork(){
return new Promise((resolve,reject) => {
setTimeout(()=>{ resolve("1. I go to Work") },100)
})
}
function sitAndWork(){
return new Promise((resolve,reject) => {
setTimeout(()=>{ resolve("2. I sit and work") },100)
})
}
function goHome(){
return new Promise((resolve,reject) => {
setTimeout(()=>{ resolve("3. I go Home") },100)
})
}
function getSleep(){
return new Promise((resolve,reject) => {
setTimeout(()=>{ resolve("4. I get sleep") },100)
})
}
gotoWork()
.then(data => {
console.log(data)
sitAndWork()
.then(data => {
console.log(data)
goHome()
.then(data => {
console.log(data)
getSleep()
.then(data => {
console.log(data)
})
})
})
})
//'1. I go to Work'
//'2. I sit and work'
//'3. I go Home'
//'4. I get sleep'
👆🏻👆🏻👆🏻
3. async/await : 콜백 체인을 다루기 위한 또다른 방법
promise의 syntactic sugar이다.
async/await를 더 알아보려면 클릭!
👇🏻👇🏻👇🏻
아래의 내용은 유튜브 "코딩앙마"님의 <자바스크립트 중급 강좌 #17 async,await>를 보고,
생각안날때 보려고 만든 자료입니다!
async라는 키워드를 앞에 두고 함수를 선언하면 결과 값이 Promise객체가 된다.
async function getName(){
return "Mike";
}
console.log(getName()) //Promise { 'Mike' }
때문에 아래와 같이 await로 연결이 가능하다.
async function getName(){
return "Mike";
}
getName().then((name)=>{
console.log(name)
})
//"Mike"
async function getName(){
return Promise.resolve('Tom')
}
getName().then((name)=>{
console.log(name)
}) //'Tom'
await 키워드는 async함수 내부에서만 사용할 수 있다. 일반함수에서는 사용불가
function getName(name){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(name);
}, 1000)
})
}
async function showName(){
const result = await getName('Mike')
//변수에 데이터가 await되었다가 들어간다는게 명확하게 보임
console.log(result)
}
console.log("시작") //시작
showName() //1초 후에 Mike찍힘
이번에는 promise코드를 async/await로 바꿔본다.
먼저 promise버전
const f2 = (message) => {
console.log(message)
return new Promise((res,rej) => {
setTimeout(()=>{
res("2번 주문 완료")
}, 3000)
})
}
const f3 = (message) => {
console.log(message)
return new Promise((res,rej) => {
setTimeout(()=>{
res("3번 주문 완료")
}, 2000)
})
}
f1()
.then((res) => f2(res))
.then((res) => f3(res))
.then((res) => console.log(res))
.catch(console.log)
그리고 같은 기능을 구현하는 async/await 버전
뭔가 순서가 한눈에 더 알기 쉽다.
const f1 = () => {
return new Promise((res,rej) => {
setTimeout(()=>{
res("1번 주문 완료")
}, 1000)
})
}
const f2 = (message) => {
console.log(message)
return new Promise((res,rej) => {
setTimeout(()=>{
res("2번 주문 완료")
}, 3000)
})
}
const f3 = (message) => {
console.log(message)
return new Promise((res,rej) => {
setTimeout(()=>{
res("3번 주문 완료")
}, 2000)
})
}
// f1()
// .then((res) => f2(res))
// .then((res) => f3(res))
// .then((res) => console.log(res))
// .catch(console.log)
console.log('시작')
async function order(){
const result1 = await f1();
const result2 = await f2(result1);
const result3 = await f3(result2);
console.log(result3)
console.log('종료')
}
order()
async/await문에선 에러가 났을떼(rejected) catch문이 아닌 try catch문으로 감싸준다.
const f1 = () => {
return new Promise((res,rej) => {
setTimeout(()=>{
res("1번 주문 완료")
}, 1000)
})
}
const f2 = (message) => {
console.log(message)
return new Promise((res,rej) => {
setTimeout(()=>{
// res("2번 주문 완료")
rej(new Error("error.."))
}, 3000)
})
}
const f3 = (message) => {
console.log(message)
return new Promise((res,rej) => {
setTimeout(()=>{
res("3번 주문 완료")
}, 2000)
})
}
console.log('시작')
async function order(){
try{
const result1 = await f1();
const result2 = await f2(result1);
const result3 = await f3(result2);
console.log(result3)
}catch(e){
console.log(e)
//에러로그 찍고
}
//그 다음 작업으로 넘어감
console.log('종료')
}
order()
👆🏻👆🏻👆🏻
function gotoWork(){
return new Promise((resolve,reject) => {
setTimeout(()=>{ resolve("1. I go to Work") },100)
})
}
function sitAndWork(){
return new Promise((resolve,reject) => {
setTimeout(()=>{ resolve("2. I sit and work") },100)
})
}
function goHome(){
return new Promise((resolve,reject) => {
setTimeout(()=>{ resolve("3. I go Home") },100)
})
}
function getSleep(){
return new Promise((resolve,reject) => {
setTimeout(()=>{ resolve("4. I get sleep") },100)
})
}
const result = async () => {
//앞에 async함수라고 표시를 해주고
//await을 사용해서 비동기 함수를 마치 동기함수처럼 쓴다.
const one = await gotoWork();
console.log(one)
const two = await sitAndWork();
console.log(two)
const three = await goHome();
console.log(three)
const four = await getSleep();
console.log(four)
}
result();
//'1. I go to Work'
//'2. I sit and work'
//'3. I go Home'
//'4. I get sleep'
콜백 에러 핸들링
const somethingGonnaHappen = callback =>{
waitingUntilSomethingHappens()
if(isSomethingGood){
callback(null,something)
}
if(isSomethingBad){
callback(something,null)
}
}
somethingGonnaHappen((err, data) => {
if(err){
console.log('ERR!!');
return;
}
return data;
})
'개념 > javaScript' 카테고리의 다른 글
[javaScript] async/await (0) | 2022.08.01 |
---|---|
[javaScript] Promise란? + 관련 메서드들 (0) | 2022.07.29 |
[javaScript] 프로토타입 체인 (0) | 2022.07.25 |
[javaScript] 정규 표현식 (0) | 2022.07.24 |
[javaScript] 프로토타입 (0) | 2022.07.22 |