[ JavaScript ] 비동기

한대희·2023년 6월 17일
0

JavaScript

목록 보기
21/23

< 동기 vs 비동기 >

1.동기적 방식

  • 기본적으로 자바스크립트 프로그램은 코드가 작성된 순서대로 코드를 실행 하게 되는데 이러한 방식을 '동기 처리 방식'이라고 한다.
//😀 단순히 콘솔에 각각 A,B,C를 출력하는 3개의 함수가 있다.
function A () {
	console.log('A')
}

function B () {
	console.log('B')
}

function C () {
	console.log('C')
}

//😀 함수는 선언이 아닌 호출 될 때 실행 되므로 아래와 같이 호출 했다면 순서대로 실행 될 것이기 때문에 
//   콘솔에 A,B,C가 찍힐 것이다.
A()
B()
C()

2.비동기 방식

  • 만약 위의 동기적 방식 예제에서 두번째 함수인 B의 처리 시간이 1분이 걸린다고 가정해 보자
  • 그렇게 되면 동기적 방식의 경우라면 B함수가 실행되는 1분동안 다음 함수인 C는 실행 되지 못하고 계속 대기하고 있기 때문에 비효율적이다.
  • 따라서 자바스크립트에서는 함수의 실행 시간이 오래 걸린다면 오래 걸리는 것은 별도로 처리를 하고 다음 코드를 실행시키게 된다. 이것이 비동기 방식이다.
function A () {
	console.log('A')
}
//😀 B함수는 setTimeout을 통해 1분뒤 콘솔에 B를 출력한다.
function B () {
	setTimeout(() => console.log('B'), 1000 * 60)
}

function C () {
	console.log('C')
}
//😀 실행 순서를 살펴 보면 먼저 A가 실행이 되고, B가 실행이 되지만 1분후 결과를 출력하므로 
//😀 일단 실행이 되고 있는 상태로 다음 코드로 넘어가게 되어 C가 실행이 된다.
A()
B()
C()

//😀 따라서 출력 결과는 아래와 같다.
A, C, 1분후 B

< 비동기 처리 >

  • 위의 예제를 통해 자바스크립트는 시간이 오래 걸리는 작업을 따로 처리하고, 다음 코드로 넘어 간다는 것을 이해했을 것이다.
  • 하지만 여기서 문제가 있다. 예를 들어 서버에서 데이터를 불러오는 함수가 있고, 그 다음에 불러온 데이터를 화면에 나타내 주는 함수가 있다고 가정해 보자.
  • 데이터를 불러오는 시간은 상대적으로 오래 걸리기 때문에 따로 처리를 할 것이고 그러면 그 다음 함수가 실행이 될 것인데, 이렇게 데이터를 불러 오기 전에 데이터를 화면에 나타내는 함수가 실행이 되면 보여줄 데이터가 없기 때문에 오류가 발생할 수 있다.
  • 따라서 이 경우는 데이터를 불러오는 함수가 실행이 끝나면 다음 함수가 실행이 되게 해야할 것이다.
  • 이렇게 실행시간이 다른 함수들을 원하는 처리 순서에 맞게 프로그래밍 하는 것을 '비동기 처리'라고 한다.

  • 이걸 가능하게 해줄 수 있는 방법은 콜백함수, Promise, async/await 이렇게 3가지가 있다.

1. 콜백함수

  • 콜백 함수란, 다른 함수의 매개 변수로 사용되는 함수다. 이 방식을 통해 비동기 처리를 구현할 수 있다.
  • 아래의 예제의 출력 결과를 보면 B함수가 1분뒤에 콘솔에 B를 출력하기 때문에 A,C,B 순서로 출력이 될 것이다.
function A () {
	console.log('A')
}

function B () {
	setTimeout(() => console.log('B'), 1000 * 60)
}

function C () {
	console.log('C')
}

A()
B()
C()
  • 이번에는 위의 예제가 A,B,C 로 출력이 되게 만들어 보자.
  • 아래와 같이 B함수는 함수를 매개변수로 받고, 해당 함수를 호출 하고 있다.
  • 그리고 B함수를 호출할 때 매개변수로 C함수를 넣어줬으므로 호출 순서에 따라 A가 먼저 실행이 되면서 콘솔에 A를 출력하고, 다음으로 B가 실행이 될 것이기 때문에 콘솔에 B가 출력이 될 것이고 그 다음으로 전달받은 콜백함수가 C가 실행이 되면서 C가 출력이 될 것이다.
  • 이처럼 세번째 함수인 C를 B함수 안에서 호출하면서 실행 순서를 조정할 수 있다.
function A () {
	console.log('A')
}

function B (callback) {
	setTimeout(() => {
    console.log('B')
    callback()
  }, 1000 * 60)d
}

function C () {
	console.log('C')
}

A()
B(C)

2. Promise

  • Promise방식은 콜백함수로 비동기 처리를 했을 경우 발생할 수 있는 콜백 지옥을 개선하기 위해 나온 방식이다.
  • 콜백 지옥이란 비동기 처리를 위해 함수의 매개 변수로 전달된 콜백함수에 또 콜백함수를 전달하고 그 함수에 또 콜백함수를 전달하게 되는 경우를 말한다.이렇게 하면 가독성이 매우 떨어지기 때문에 Promise라는 방식이 도입 되었다.

Promise 작동 원리

  • 먼저 Promise를 사용하려면 Promise객체를 만들어야 한다.
  • 만들어진 Promise객체는 resolve라는 콜백함수와 reject라는 콜백함수를 매개변수로 사용하게 된다.
  • Promise 방식은 함수가 성공적으로 실행이 되면 resolve함수를 호출 하고, 실패 하면 reject함수를 호출 한다.
  • 따라서 Promise객체는 아래와 같이 생성한다.
new Promise((resolve, reject) => {
  // 실행할 코드 작성
})

Promise 예제

  • 예제를 통해 이해해 보자.
  • 예제를 보면 coffee라는 promise 객체를 만들 었고 promise객체 안의 코드가 성공적으로 실행이 되면 즉, likeCoffee가 true면 resolve가 실행이 될 거고 likeCoffee가 false 즉, 실패 하면 reject가 실행이 될 것이다.
  • 따라서 각각의 reslove()와 reject()에 성공과 실패 메세지를 전달을 했다.
let likeCoffee = true
const coffee = new Promise((resolve, reject) => {
	if (likeCoffee) {
    	resolve('커피 주문 성공')
    } else {
    	reject('커피 주문 실패')
    }
})
  • 그러나 여기 까지만 살펴 보면 성공하거나 실패했을때 어떤 값만 전달할 뿐 그 이후 뭘 해줄 건지 명령을 해주지 않았다.
  • 이 명령을 하기 위해서는 then메서드, catch메서드, finally메서드를 사용해야 한다.
  • then메서드는 Promise객체의 코드가 성공적으로 실행이 되어서 resolve가 호출 되었을 때 resolve에 전달된 값을 받는 역할을 한다. resolve 함수로 매개변수를 전달을 한거고, resolve함수 내부에서 뭔가 처리를 할때는 then안에서 하면 되는 것이다.
  • catch메서드는 reject가 호출이 되었을 때 에러메세지를 받는 역할을 한다.이것 역시 Promise객체 내부에서 reject함수에 매개변수로 값을 전달을 해주면 어떤 처리를 해야 할텐데 그것을 catch안에서 해주면 되는 것이다.
  • finally메서드는 Promise객체의 코드가 성공적으로 실행이 되는 안되던 무조건 무언가를 실행하고 싶을 때 사용하게 된다.
  • 사용법은 아래와 같다.
let likeCoffee = true
const coffee = new Promise((resolve, reject) => {
	if (likeCoffee) {
    	resolve('커피 주문 성공')
    } else {
    	reject('커피 주문 실패')
    }
})
  
  //😀 likeCoffee변수가 true면 Promise객체 내부에서 resolve함수에 '커피주문성공'이라는 매개변수를 전달을 할 것이고
  //😀 전달받은 매개 변수를 가지고 then안에서 처리를 해준 것이다.
  //😀 만약 likeCoffee변수가 false라면 Promise객체 내부에서 reject함수에 '커피주문실패'라는 매개변수를 전달을 할 것이고
  //😀 catch에서 전달받은 매개 변수를 가지고 어떤 처리를 해주면 된다.
  coffee
  	.then(res => console.log(res))
  	.catch(err => console.log(err))
  • 이게 왜 비동기 처리인지 이해가 가지 않는 다면 Prmoise객체 내부의 코드가 서버에서 데이터를 불러오는 코드라고 생각해 보자.그리고 해당 데이터를 가지고 화면에 렌더링 하는 함수가 있다고 생각해 보자.
  • 그러면 서버에서 데이터를 온전히 가져오기 전에 화면에 렌더링을 하는 함수가 호출이 된다면 화면에 아무것도 렌더링이 되지 않을 것이기 때문에 데이터를 다 가져오면 렌더링 함수가 호출이 되야 할 것이다.
  • 따라서 Prmoise객체 내부의 코드인 데이터를 불러오는 과정이 성공적으로 실행이 된다면, resolve함수에 받아온 데이터를 전달을 할 것이고 그러면 then안에서 해당 데이터를 받아와 렌더링 함수의 매개변수에 넣어주면 코드의 실행 순서를 조정하는 비동기 처리가 되는 것이다.

3. async / await

  • async / await 방식은 Promise의 문제점을 보완하기 위해서 나온 방식이다.
  • Promise를 사용하면 콜백지옥의 문제를 해결 할 수 있지만 Prmoise의 경우도 여러개의 then과 catch를 사용하게 되면 콜백지옥과 비슷한 문제가 발생할 수 있다.

async / await 사용법

  • 사용법은 간단하다. 그냥 함수 앞에 async를 붙이면 해당 함수는 자동으로 Promise를 반환하는 함수로 바뀌게 된다.
//😀 coffee라는 함수가 있고, 이 함수는 아래와 같이Prmoise를 리턴한다.
//😀 이렇게 함수가 Prmoise를 리턴하게 하면 함수가 복잡해 진다.
  function coffee () {
  	return new Promise((resolve, reject) => {
      	if (likeCoffee) {
                resolve('커피 주문 성공')
            } else {
                reject('커피 주문 실패')
            }
          }  
	}
  
  
//😀 async를 붙이면 자동으로 Promise를 리턴하기 때문에 훨씬 간단하게 적을 수 있다.
//😀 coffee라는 함수는 변수 val이 true면 그냥 '커피주문성공'메시지를 리턴하고, false면 '커피주문실패'메세지를 전달하고 있다.
//😀 하지만 async를 붙였기 때문에 Prmoise를 리턴하는 것이므로 사실상 resolve('커피 주문 성공'), reject('커피 주문 실패') 
//😀 를 전달한 것과 똑같다.
async function coffee () {
  let val = true
  if(val) {
    return '커피주문성공'
  } else {
    return '커피주문실패'
  }
}

//😀 따라서 똑같이 then과 catch를 통해 해당 값을 받아올 수 있다.
  Coffee()
  .then(res => console.log(res))  // '커피주문성공'
  .catch(err => console.log(err)) // '커피주문실패'
  
  
//😀 그러면 Caffee라는 함수가 있고, 해당 함수 안에서 coffee라는 함수가 호출이 되고, coffee라는 함수가 성공적으로 실행이 되면 커피를 만드는 makeCoffee함수가 있다고 생각해 보자.
  
  //😀 Cafe라는 함수가 있고  
  async function Cafe () {
    const res = Coffee()
    const result = makeCoffee(res)
  }
  
  //😀 Coffee함수가 있고
  async function Coffee () {
  let val = true
  if(val) {
    return '커피주문성공'
  } else {
    return '커피주문실패'
  }
}
  
  //😀 makeCoffee함수가 있다.
  async function makeCoffee (res) {
  if(res === '커피주문성공') {
    return '커피제조중'
  } else {
    return '주문안들어옴'
  }
}
  
 //😀 다시 Cafe함수로 돌아가 보면 내부에서 Coffee함수가 실행이 끝나면 응답을 받아 makeCoffee함수의 매개변수로 전달을 하고 있다.
 //😀 이때 사용할 수 있는 것이 await이다. 그냥 await을 붙이면 해당 함수가 실행이 끝날때 까지 기다린다.
 //😀 따라서 Coffee함수가 성공적으로 실행이 되면 '커피주문성공'이 res에 전달이 될 것이고
 //😀 그 다음 makeCoffee함수가 res를 전달받아 '커피제조중'을 리턴하게 될 것이다.
    async function Cafe () {
    const res =  await Coffee()
    const result = await makeCoffee(res)
 	console.log(result)
  }
  
  
//🔥 즉 async만을 사용하여 then과 catch를 이용해서 코드 실행순서를 조정하는 비동기 처리를 하던지,
//🔥 아니면 await을 이용하여 비동기 처리를 하면 되는 것이다.
profile
개발 블로그

0개의 댓글

관련 채용 정보