동기&비동기

원녕·2022년 12월 20일
0

1,2,3,4 순서에 따라 처리되는것이 아닌 먼저 처리된 코드를 우선순위를 두고 실행시켜주는 코드.
비동기 함수의 종류에는 콜백함수,promise함수,async,await 함수가 있다.

1. 콜백함수 (동기&비동기)

함수자체를 인자로 전달하는 함수를 의미

settimeout함수로 함수를 전달하면 그것도 콜백

//비동기식 프로그래밍 1->3->2 순으로 콘솔에 찍힌다.
console.log('1')
setTimeout(function() {
    console.log('2')
},1000)
console.log('3')

쉽게 말하자면 콜백함수는 말그대로 호출용이고
(인자 전달 및 callback호출용도) 내부에 함수 실행 코드는 없다. 콜백함수랑 같이 쓰일 함수가 더 있어야한다(함수 실행 코드).

function first(callback){
  setTimeout(() => {
    console.log("10초 뒤 실행");
    callback();
  }, 10000);
}
function second(){
  console.log("저는 first다음으로 실행해주세요~~");
} 
first(second);

이 함수는 일반적인 callback의 유형이다. 대신 first가 실행되기전에 second는 손가락만 쪽쪽 빨고있어야한다. 이유는 first안에 second로 매개변수를 던져서 first에 제어권한이 있기 때문이다. 즉 second가 이미 준비 완료가 되어있어도 first가 준비되기 전까지는 호출이 되어지지 않는다는 뜻이다.

ex ) 매표소 -> 매표소에서 표를 사려고 지갑을 꺼내서 맞는 금액을 손에 쥐고있어도 당신은 바로 살수가 없다. 그앞에있는 사람이 존재하기 때문이다.

callback을 안쓴 동기함수 버전

function func1(){ 
  console.log("1번입니다"); 
  func2(); 
} 
function func2(){ 
  console.log("2번입니다"); 
  func3(); 
} 
function func3(){ 
	console.log("3번입니다"); 
} 

func1(); 
//1번입니다 
//2번입니다 
//3번입니다

다음은 callback을 사용하지 않은 비동기 함수의 예시다.

function func1(){ 
  console.log("1번입니다"); 
  func2(); 
} 
function func2(){ 
  setTimeout(
    console.log("2번입니다");
    , 3000
  ); 
  func3(); 
} 
function func3(){ 
	console.log("3번입니다"); 
} 

func1(); 
//1번입니다
//3번입니다 
//2번입니다

정리 : func1은 2를 호출하면서 먼저 실행되는 함수고 func2는 시간차가 있는 즉 비동기적 함수고 func3는 2에서 호출되는 함수지만 func2의 시간차를 고려해 func2보다 먼저 실행되었다

1-1 비동기방식의 문제점
바로 데이터통신이 되기도 전에 값을 return해버리게 되거나 이 값을 이용하는 어떠한 동작이 동시에 이루어질 경우 undefined값을 사용할 수 밖에 없다.

1-2 콜백지옥 (계단식 논) => 가독성 구려,실제로 데이터가 전달되지 않는 채로 호출될 상황 발생 가능성

function Callback(callback){
    function Callback2(callback){
        function Callback3(callback){
            console.log('무한콜백');
        }
    }
}

2. promise함수

Promise의 세가지 상태(States)

Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태

Pending 상태 예시
아래와 같이 Promise 객체를 생성하는 시점부터 Pending상태이다.
또한 콜백함수의 인자로서 resolve,reject를 받을 수 있다.

new Promise(function(resolve, reject) {
  
}); 

Fulfilled(이행) : 비동기 처리 로직이 수행완료되어 결과 값을 반환한 상태

new Promise(function(resolve, reject) {
  resolve();
}); 

Rejected(실패) : 비동기 처리가 실패하거나 에러가 발생한 상태

new Promise(function(resolve, reject) {
  rejected();
}); 

아래는 동기 방식 코드다.

new Promise((r1, r2) => {
    console.log('Hello Promise1!');
    r1();
})
.then(() => {
    console.log('Hello Promise2!');

    new Promise((r1, r2) => {
        console.log('Hello Promise3!');
        r1();
    })
    .then(() => {
        console.log('Hello Primise4!');
    })
})

문제는 then 안에 new Promise를 계속 생성하면, 위에서 봤었던 Callback지옥에 빠지게 될 것이다.
이러한 문제를 해결하도록 내부에서 실행되는 Promise는 return을 시켜주자. 그러면 내부에 있던 Promise가 Scope에서 탈출하기 때문에 내부에 있던 Promise의 then을 내부에서 아닌 외부에서 호출을 할 수 있게 된다.

const promise = new Promise((resolve,reject) =>{
    //doing someting heavy work (network or data)
    console.log("Doing Something")
    setTimeout(()=>{
        resolve('2초 지남');
    },2000)
	return promise;  // 이 함수는 동기적 방식  
})

//2. Consumer: then, catch, finally
promise
.then((value) => {
    console.log(value);
})
.catch(error => {
    console.lot(error);
})
.finally(()=>{
    console.log("finally")
})

promise 퀴즈 풀어보기 : https://nukw0n-dev.tistory.com/17 이 퀴즈도 정말 유용할듯하다.

3 .async,await 비동기함수

Async와 Await을 사용하려면 우선 사용할 함수 앞에 async라는 키워드를 붙여 사용해야 하며 선언된 async 함수 안에서만 await 키워드를 사용할 수 있다.

async & await 기본 문법
먼저 함수의 앞에 async라는 예약어를 쓴다.그리고 해당 함수 내에서 비동기 처리 로직을 수행하는 메서드 앞에 await 예약어를 붙여준다. 여기서 비동기 처리 메서드는 꼭 Promise객체를 반환해야함.

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
  //2초동안 기다리게 하고 사과를 리턴하는 메서드
  async function getApple() {
    await delay(2000);
    return '🍎';
  }
  //1초동안 기다라게 하고 사과를 리턴하는 메서드
  async function getBanana() {
    await delay(1000);
    return '🍌';
  }
getApple().then(console.log);
getBanana().then(console.log);
const TestApiCall = () {
  axios.get('https://test.com/api/v1')
    .then((response) => {
      const data = response.data;
      const userId = data.userId;
      axios.get('https://test2.com/api/v2/' + userId)
        .then((response) => {
          console.log("Response >>", response.data)
        })
        .catch(() => {
        })
    })
    .catch((error) => {
      console.log("Error >>", err);
    })
}

다음 코드가 이렇게 수정될 수 있다.

const TestApiCall = async () {
  try {
    const response = await axios.get('https://test.com/api/v1')
    const userId = response.data.userId;
    const response2 = await axios.get('https://test2.com/api/v2/' + userId);
    console.log("response >>", response2.data)
  } catch(err) {
    console.log("Error >>", err);
  }
}
profile
메타인지하는 개발자

1개의 댓글

comment-user-thumbnail
2022년 12월 23일

굿...

답글 달기