Promise와 Async/await

jh_leitmotif·2021년 7월 22일
0

JS 개념 정리

목록 보기
1/4
post-thumbnail

🧐 개요

JS 강의 속, 프로미스와 비동기식 프로그래밍이 있었습니다만....

역시나 저는 보기 좋게 까먹어버리고, 문제가 발생했죠 😅

주구장창 개발하던 중, DB 작업과 관련해 비동기 작업의 순차작업이 필요했고

그것을 해결하는 과정을 담는 겸 개념을 정리합니다.


😡 What's The Problem?

첨부된 파일을 사용자가 다운로드하게 될 때

클라이언트는 파일의 원본 이름을 보고 클릭하지만

서버 쪽은 파일 이름이 다른 파일과 동일할 수 있는 문제점이 있기 때문에
미리 특정 패턴으로 변경하여 저장해둔다는 점이 있습니다.

따라서 파일 이름, 포스트의 ID로 DB로부터 파일의 실제 경로를 확인하는데

포스트에 여러개의 파일이 첨부된 경우,
컬럼이 2개 이상의 파일주소를 담으므로 스트링을 나눠야할 필요성이 있습니다.


  1. 사용자가 파일을 클릭하여 다운로드를 요청
  2. 서버는 포스트 ID와 파일 이름을 DB로 전달
  3. DB는 정보를 토대로 파일 경로를 서버로 전달
  4. 서버는 경로 정제 후 파일 존재 여부를 확인
  5. 파일 전달

여기서 경로를 정제하기 전, DB의 작업은 무조건 선행되어야합니다.

그런데 SQL Fetch에는 일정 시간이 소요되므로

3번이 끝나기도 전에 4번이 먼저 실행되면서 오류가 발생되었습니다.


🙄 Solution?

첫 번째 시도했던 방법은 setTimeout 입니다.

conn.getConnection((err,rows)=>{
 if (err) throw err;
  connection.query(sql,(err,rows)=>{
   str = filepath;
   connection.release();
  }
}
setTimeout(function(){
   fileList = str.split('+');
   res.download(fileList[0],originalFileName);
},1000)

// 완전한 코드가 아닙니다. 제 코드가 너무 길어 상징성 있는 것을 빼곤 지웠습니다.

스트링을 정제하는 4번 단계가 약간 뒤에 발생하도록 만들어
DB작업이 먼저 처리되도록 만들었습니다.

그러나 DB에 오류가 있을 수도 있고, 또는 페치 시간이 얼마나 길지 모르기에

다른 방법을 찾게 되었고, Promise Async/Await 구조로 변경했습니다.

개념을 잡는 데에 1~2시간은 걸린 것 같습니다 😅 ..


📋 What is Promise?

Promise는 JavaScript의 ES6에 추가된 개념입니다.

비동기적 작업들을 순차적으로 진행할 필요가 있을 때에

무수한 콜백 중첩이 생기곤하는, 즉 Callback hell 현상을 해결합니다.

프로미스 객체는 세 가지 상태를 가집니다.

  1. 프로미스 객체가 생성되면 [ pending ] 상태
  2. 성공 또는 에러입니다.
    2-1. 성공시 [ fulfill ] 상태가 되면서 .then으로 옮겨갑니다. 여기에서 비동기 처리 이후 작업될 것을 작성하면 됩니다.
    2-2. 오류시 [ reject ] 상태가 되어 에러 핸들링을 진행합니다.
  3. 만약 체이닝된 프로미스가 있으면 그 객체로 넘어갑니다.
//프로미스 생성
const work1 = function(a){
  return new Promise(function(resolve,reject){
    if(a){
      resolve("성공");
    }
    else{
      reject("실패");
    }
  });
}
//프로미스 실행
work1(true).then(function(result){
  console.log(result); // 성공
},function(err){
  console.log(err); // 실패
});

위 코드의 경우 다음과 같이 진행됩니다.

  1. work1 프로미스 객체 생성, pending 상태
  2. 프로미스 실행 단에서 work1에 true 파라미터 전달
  3. 파라미터가 있는 경우 resolve되어 .then으로 이동
  4. .then 내부에 있는 함수 실행

단순히 성공/실패 여부를 출력하기만 하지만

만약 work1에 선행 작업을 작성하고, then에 후행 작업을 넣을 수도 있겠습니다.

const work1 = function(){
	const a = true;
	const work2 = function(param){
    		if (param){
            		console.log('성공!')
           	else{
            		console.log('실패!')
            	}

콜백 함수 형태로 작성하면, 지금은 2개의 작업 밖에 없지만
복잡한 작업이 추가되면 추가될 수록 눈이 아플겁니다 😡

어쨌든 중요한 것은 Promise 객체는 곧 상태와 같다는 것입니다.

✔ Promise Chaining

Promise의 .then을 이용하여 선/후행 작업을 간단하게 컨트롤할 수 있습니다.

work1(true).then(function(){
	console.log('작업1');
}).then(function(){
	console.log('작업2');
}).then(function(){
	console.log('작업3');
}).catch(function(err){
	console.log(err);
}

이런 방식으로 자칫 복잡할 수 있는 3중 콜백 작업을 표현할 수 있습니다.

또한 위에선 catch에서 에러만 출력하지만, 프로미스 객체를 같이 리턴한다면

체이닝을 이어갈 수 있습니다.


📋 Async와 Await

콜백과 프로미스의 단점을 보완하고 가독성을 향상시키는 문법입니다.

이 문법에서 초점으로 둔 것은 '보이는대로 읽히도록' 인 것 같습니다.

async function Test(){
	let tempVar = await tempFunc();
    	if (tempVar.status == true)
    		console.log('완료!');
}

await가 사용되는 함수에는 async를 꼭 붙여야합니다.

그리고 await 키워드가 붙은 함수가 처리되어야 그 다음 작업이 진행됩니다.

즉, tempFunc()의 상태가 완료되어야만 그 뒤 if문이 실행됩니다.


앞서 언급한 것 중, Promise 객체는 상태를 가진다고 했습니다.

즉, Async/Await는 Promise와 결합했을 때 더욱 빛을 발합니다.

let work1 = function(a){
	return new Promise(function(resolve,reject){
    		if(a){
      			resolve("성공");
          	}
    		else{
     			reject("실패");
    		}
	});
}

let work2 = function(b){
	return new Promise(function(resolve,reject){
    		if(b){
            		resolve("성공");
                else{
                	reject("실패");
                }
        });
}

let worker = async function(){
	console.log(await work1(a));
    	console.log(await work2(a));
}

worker().then(function(){
	console.log('추가 작업?')
}

간단한 예제를 작성해보았습니다.

worker 변수에 Async / Await로 맺어진 함수가 있고,

그에 따라 work1이 선행되면 work2가 후행되는 구조입니다.
위에 작성한 Promise Chaining과 매우 유사해보입니다.

맨 아래 .then을 통해 또 다시 후행 작업을 정의할 수도 있습니다.


🎯 그래서 뭐가 제일 좋아?

Callback, Promise, Async/Await.

모두 작업결과 자체는 동일하지만 가독성에 대한 차이가 있어서 개인차가 있을 것 같습니다!

개인적으로는 Async/Await로 코드 자체도 모듈화처럼 꾸미려고 합니다.

내일은 수많은 콜백 함수들을 새로 배운 개념으로 바꾸는 작업을 해야겠네요..😱

profile
Define the undefined.

0개의 댓글