Be ready to study forever - 개발자 꿈나무

동기/ 비동기의 이해 - callback함수, promise, async, await 본문

Programming/JS

동기/ 비동기의 이해 - callback함수, promise, async, await

루눌룹 2020. 8. 14. 15:41

1. 동기/ 비동기란?

동기(Synchronized)란 쉽게 설명해서 프로그램이 작성된 순서대로 실행되는 것으로 A, B, C 순서로 함수가 작성되어 있다면 함수는 반드시  A, B, C순서대로 A의 동작이 끝나면 B함수가 실행되고, B가 끝나면 C함수가 동작하는 것을 동기적 실행이라고 할 수 있다.

//예제코드
function firstFunction(){
  //내용내용
  console.log(1);
}

function secondFunction(){
  //내용내용
  console.log(2);
}

function ThirdFunction(){
  //내용내용
  console.log(3);
}

firstFunction();
secondFunction(); 
ThirdFunction(); 

firstFunction( ) 시작 -> firstFunction( ) 완료 -> secondFunction( )시작 -> secondFunction( )완료 ->thirdFunction( )시작 -> thirdFunction( )완료 로 실행되어 하나의 타임라인으로 실행된느 것을 동기적 실행이라고 한다.

예제코드의 결과(실행 순서: firstFunction -> secondFunction -> thirdFunction)

비동기(Asynchronized)란 동기적 실행이 하나의 타임라인으로 A가 완료되면 B가 실행되고 B가 완료되면 C가 실행되는 것과는 달리 비동기 프로그래밍은 타임라인의 분기를 나눠서 두개이상 함수가 동시에 동작하는 것이다. 대표적인 예제로 Timeout( )이 있는데 Timeout( )을 쓰게 되면 기적 타임라인에서 나눠저서 독자적으로 함수를 실행하게 된다.

setTimeout()함수를 사용하면 기존의 타임라인에서 분기를 만들어 독자적으로 실행되도록 한다.

 

//비동기 실행의 예제코드
function firstFunction(){
  //내용내용
  console.log(1);
}

function secondFunction(){
  //내용내용
  console.log(2);
}

function ThirdFunction(){
  //내용내용
  console.log(3);
}

firstFunction();
setTimeout(secondFunction,3000); //3000ms후 실행한다는 의미
ThirdFunction();

예제코드 실행결과, secondFunction은 따로 타임라인에서 분리되어서 3초를 기다린후 실행되기 때문에 1,3,2 순서로 실행된다.

2. Callback함수

콜백함수란 함수에 매개변수로 전달받아서 실행하는 함수이다. 그럼 콜백함수는 왜 필요한가? 비동기로 함수를 실행할 경우 라도 논리적으로 A동작이 완료되고 B동작이 실행되어야 하는 경우가 있다. 예를들면 텍스트파일이나 서버로부터 비동기로 파일을 읽는동작(동작A) 과 읽은 파일을 가공하는 동작(동작B)가 있는 경우이다. 이럴경우 에 B를 콜백함수로 A함수의 인자로 호출하면 이를 방지하고 A가 동작을 완료하고 B를 실행 할 수가 있다.

function square(num) {
  console.log(num);
  let number = num * num;
  console.log(number);
}

function plus(callback) {
  const a = 3;
  const b = 2;

  const sum = a + b;

  callback(sum);
}

//square라는 함수에 setTimeout안에 함수의 리턴값을 넣고 실행
// 3000ms 동안 기다렸다가 실행되므로 return값이 제대로 없는 상태에서 sqaure함수가 실행된다.
square(
  setTimeout(() => {
    const a = 3;
    const b = 2;

    const sum = a + b;

    return sum;
  }, 3000)
);

//콜백함수를 이용하여 실행 
//square라는 콜백함수가 plus라는 함수내에서 실행되어서 plus() -> square() 순서로 실행된다
setTimeout(plus(square), 3000);

 그러나 A함수를 비동기로 실행하여 B함수 C함수 D함수와 같은 순서로 실행하고자 한다면 계속 A함수안에 B를 콜백함수로, B함수 안에 C함수를 콜백함수로, C함수 안에 D함수를 콜백함수로 넣어서 코드가 보기에 괭장히 복잡해 진다. 이를 클백지옥이라고 부른다고 한다.

function increaseAndPrint(n, callback) {
  setTimeout(() => {
    const increased = n + 1;
    console.log(increased);
    if (callback) {
      callback(increased);
    }
  }, 1000);
}

increaseAndPrint(0, n => {
  increaseAndPrint(n, n => {
    increaseAndPrint(n, n => {
      increaseAndPrint(n, n => {
        increaseAndPrint(n, n => {
          console.log('끝!');
        });
      });
    });
  });
});

이러한 문제점을 해결하기 위해 나온것이 promise이다. 비동기적 실행에서 순차적으로 실행시켜야 할경우 콜백함수를 이용해서 실행하는 것 대신에 promise를 활용하면 훨씬더 보기 깔끔한 프로그래밍이 실행된다.

3. promise

위에서도 언급했지만 promise는 비동기 처리를 실행하고 비동기 처리가 끝난 다음 코드를 순차적으로 실행하기 위해 사용되며 promise를 사용하기 위해서는 promise객체를 생성해야한다.

let promiseInstance = new promise(function(resolve, reject){//내용내용});

 

promise는 실패를 할 경우도 존재한다. 따라서promise가 성공할 경우에는 resolve에 리턴할 값을 담고, promise작업이 실패할 경우애는 reject에 에러메세지 등을 담는다. 즉, 프로미스 안에 resolve와 reject가 동시에 존재할 수가 없다.(보통은 if절로 분기를 나눠서 resolve와 reject를 적는다.)

let promise1 = new Promise((resolve, reject) => {
  //promise 생성
  setTimeout(() => {
    resolve(3);
    console.log(1);//3000ms후 실행
  }, 3000);
});

promise1.then((value) => {//then의 익명함수에서 받은 매개변수는 resolve에 들어있는 값을 받는다.
  //then안에 promise다음에 실행될 함수를 실행시킨다
  console.log(2);
  console.log(value);//value는 resolve에 들어서 반환된 값
});

 

reject가 실행 될 경우 promise다음에 오는 then은 실행되지 않는다 대신에 .catch()로 reject의 값을 받아서 에러처리를 할 수 있다.

let promise1 = new Promise((resolve, reject) => {
  //promise 생성
  setTimeout(() => {
    reject("그냥 실패");//안에 있는 값은 catch()에서 받아서 사용한다
  }, 3000);
});

promise1.then((value) => {//then의 익명함수에서 받은 매개변수는 resolve에 들어있는 값을 받는다.
  //then안에 promise다음에 실행될 함수를 실행시킨다
  console.log(2);
  console.log(value);//value는 resolve에 들어서 반환된 값
}).catch((e)=>{//e는 reject에 들어있는 값이다.
	console.log(e)
    });

 

여러개의 promise를 만들어서 순차적으로 돌릴 수 도 있다.

//예제코드

function plusOne(number){//프로미스 정의
  return new Promise(function(resolve, reject){
    resolve(number+1);
  });
}

function plusTwo(number){//프로미스 정의
  return new Promise(function(resolve, reject){
    resolve(number+2);
  });
}

function plusThree(number){//프로미스 정의
  return new Promise(function(resolve, reject){
    resolve(number+3);
  });
}

plusOne(1).then(function(value){
  console.log(value);
  return plusTwo(value); //return값에 pluseTwo프로미스를 넣어 줌으로 서 다음에 then()을 또 쓸수 있다
}).then(function(value){
  console.log(value);
  return plusThree(value);//return값에 pluseThree프로미스를 넣어 줌으로 서 다음에 then()을 또 쓸수 있다
}).then(function(value){
  console.log(value);
})

예제코드 실행 결과

4. Async, Await

promise를 좀더 편하고 간편하게 사용하기 위해서 나온것이 Async /Await이다. 사용방법은 간단하다. 함수앞에 Aysnc 를 붙여주고 비동기로 실행된 함수 앞에 await을 넣어주면 말그대로 비동기로 실행된 결과가 끝날때 까지 기다린다.

Async를 앞에 붙이면 그 함수는 return으로 프로미스를 반환하게 된다.


References

https://learnjs.vlpt.us/async/01-promise.html
youtu.be/VMO4yX7kkW8
 

01. Promise · GitBook

01. Promise 프로미스는 비동기 작업을 조금 더 편하게 처리 할 수 있도록 ES6 에 도입된 기능입니다. 이전에는 비동기 작업을 처리 할 때에는 콜백 함수로 처리를 해야 했었는데요, 콜백 함수로 처��

learnjs.vlpt.us

 

 

Comments