promise

김민지·2022년 9월 8일

프론트

목록 보기
13/13

콜백 지옥

class UserStorage{
        loginUser(id, pw, onSuccess, onError){
          setTimeout(()=>{
            if(
              (id ==='ellie' &&  pw === '1234') || 
              (id === 'coder' && pw === '12345')
            ){
              onSuccess(id);
            }else{
              onError(new Error(" not found!!!0"))
            }
          }, 2000);
        }

        getRole(user, onSuccess, onError){
          setTimeout(()=> {
            if(user==='ellie'){
              onSuccess({name: 'ellie', role: 'admin'});
            }else{
              onError(new Error('no acceess'));
            }
          }, 1000);
        }
      }
      const storage = new UserStorage();
      storage.loginUser("ellie", "1234", (id)=>{
        storage.getRole(id, (user)=> console.log(user.name +"    "+ user.role),()=> console.log("엥 에러남")  )
      

문제점
1. 가독성 ↓
2. 유지보수 힘듦

-> 비동기 코드를 효율적으로 작성해보자 -> promise 활용

promise

콜백함수를 쓰지 않고, promise를 활용해서 비동기코드를 깔끔하게 처리해보자

  1. state : 기능 수행중(pendind), 완료, 실패
  2. producer, consumer의 차이
const promise = new Promise((resolve, reject) => {
    //heavy한 비동기적인 일 수행
    console.log("doing something...");
  	setTiemout(()=> {
      resolve('ellie');
    }, 2000);
    })
//정상적으로 수행이 된다면 어떠한 value를 받아올 것이다
//resolve에서 넘겨준 'ellie'가 value에 들어올 것이다
//then과 catch는 promise를 반환하기 때문에 체이닝이 가능
promise.then((value) =>{
   console.log(value);
}).catch(error -> {
   console.log(error);
}).finally(()=>{
  console.log("finally");
});
  • promise가 만들어지는 그 순간 그 안에 정의 되어있는 콜백함수가 실행됩니다
  • promise는 어떤일을 2초정도 하다가 일을 잘 했어서 resolve를 출력하는 promise임.
  • 이 promise를 이용하는 consumer를 활용하자
  • 비동기적인 일을 수행하는 코드를 promise에 정의한다
  • 그 일이 완료되었을때 일을 then에 정의하고 실패했을때의 에러 처리 코드를 catch에 정의한다
  • finally는 성공하든 실패하든 상관없이 항상 호출되는 코드
  • promise는 바로 실행되고, 결과를 저장한다

error handling

const getHen = () =>
  			new Promise((resolve, reject) => {
      		setTimeout(() => resolve('🐓'), 1000);
  		});
			const getEgg = hen =>
  			new Promise((resolve, reject) => {
    			setTimeout(() => resolve(`${hen} => 🥚`), 1000);
              //setTimeout(() => reject(new Error('달걀없슴'), 1000);
  		});
			const cook = egg =>
  			new Promise((resolve, reject) => {
    			setTimeout(() => resolve(`${egg} => 🍳`), 1000);
 			 });

			getHen() //
  			.then(getEgg)
        .catch(error => {
        	return '🍔';//만약에 error가 났을 시에는 빵을 대신 전달해준다
        })
  			.then(cook)
  			.then(console.log)
  			.catch(console.log);

기본 개념

promise는 비동기 작업의 단위 이다
callback함수는 인자로 함수를 받는 함수이다

let promise = new Promise(function(resolve, reject) {
  // executor 부분
});
  • executor는 보통 시간이 걸리는 일을 수행합니다. 일이 끝나면 resolve나 reject 함수를 호출하는데, 이때 프라미스 객체의 상태가 변화합니다.

  • promise 생성자는 함수를 인자로 받습니다. 이 함수를 executor 라는 이름으로 부릅니다.

  • Promise 의 특징은 new Promise(...) 하는 순간 여기에 할당된 비동기 작업은 바로 시작됩니다. 비동기 작업의 특징은 작업이 언제 끝날지 모르기 때문에 일단 배를 떠나보낸다고 이야기했습니다. 그럼 그 이후에 이 작업이 성공하거나 실패하는 순간에 우리가 또 뒷처리를 해줘야겠죠? Promise 가 끝나고 난 다음의 동작을 우리가 설정해줄 수 있는데, 그것이 바로 then 메소드와 catch 메소드입니다.

  • then 메소드는 해당 Promise 가 성공했을 때의 동작을 지정합니다. 인자로 함수를 받습니다.
    catch 메소드는 해당 Promise 가 실패했을 때의 동작을 지정합니다. 인자로 함수를 받습니다.

예제

1초 뒤에 promise1,2 의 age에 따라 실행결과를 출력하는 메서드를 구현해보세요

function startAsync(age) {
  return new Promise((resolve, reject) => {
    if (age > 20) resolve();
    else reject();
  });
}
setTimeout(() => {
  const promise1 = startAsync(25);
  promise1
    .then(() => {
      console.log("1 then!");
    })
    .catch(() => {
      console.log("1 catch!");
    });
  const promise2 = startAsync(15);
  promise2
    .then(() => {
      console.log("2 then!");
    })
    .catch(() => {
      console.log("2 catch!");
    });
}, 1000);

async: 비동기 작업을 만드는 손쉬운 방법

  • 함수에 async 키위드를 붙입니다.
    new Promise... 부분을 없애고 executor 본문 내용만 남깁니다.
    resolve(value); 부분을 return value; 로 변경합니다.
    reject(new Error(…)); 부분을 throw new Error(…); 로 수정합니다.
function startAsync(age) {
  return new Promise((resolve, reject) => {
    if (age > 20) resolve();
    else reject();
  });
}
async function startAsync(age) {
  if (age > 20) return `${age} success`;
  else throw new Error(`${age} is not over 20`);
}
  • async 함수의 리턴 값은 무조건 Promise 입니다 !
  • 프라미스 객체의 state, result 프로퍼티는 내부 프로퍼티이므로 개발자가 직접 접근할 수 없습니다. .then/.catch/.finally 메서드를 사용하면 접근 가능합니다
  • finally : 디비같은거에 커넥션했는데 오류가나더라도 연결을 끊어주는 과정은 꼭 필요하니까 그런경우에 사용(즉, 실패하든 성공하든 공통적으로 해야할 일을 지정해주어야할 때)

프라미스 객체의 state, result에 접근하기

let promise = new Promise(function(resolve, reject) {
  setTimeout(() => resolve("완료!"), 1000);
});

// resolve 함수는 .then의 첫 번째 함수(인수)를 실행합니다.
promise.then(
  result => alert(result), // 1초 후 "완료!"를 출력
  error => alert(error) // 실행되지 않음
);

.then의 첫 번째 인수는 프라미스가 이행되었을 때 실행되는 함수이고, 여기서 실행 결과를 받습니다.
.then의 두 번째 인수는 프라미스가 거부되었을 때 실행되는 함수이고, 여기서 에러를 받습니다.
첫번째 줄에서 resolve가 아니라 reject결과가 나왔다면 error를 출력했겠지

에러 발생 시에만 처리

  • 에러가 발생한 경우만 다루고 싶다면 .then(null, errorHandlingFunction)같이 null을 첫 번째 인수로 전달하면 됩니다. .catch(errorHandlingFunction)를 써도 되는데, .catch는 .then에 null을 전달하는 것과 동일하게 작동합니다

비동기 처리

  • js는 동기적이다. 순차적으로 실행된다는 의미이다.
  • 콜백함수 : 전달해준 함수를 나중에 네가 불러줘! 의 개념
  • setTimeOut(callback함수(), 초)
  • 원래는 순차적으로 실행하는데 setTimeout의 time을 시작시켜놓고 다음 코드를 실행시키는 것

callback vs promise

callback을 사용하면 비동기 로직의 결과값을 처리하기 위해서는 callback안에서만 처리를 해야하고, 콜백 밖에서는 비동기에서 온 값을 알 수가 없습니다. 하지만 promise를 사용하면 비동기에서 온 값이 promise 객체에 저장되기 때문에 코드 작성이 용이해집니다.

  • 함수의 처리 순서를 보장하기 위해서 함수를 중첩하게 사용되는 경우가 발생

callback말고 promise를 쓰는 이유

return value를 이용할 수 있다는 점
error handling이 동기식 코드와 유사하게 쓰일 수 있다는 점

헷갈렸던 점

const getHen = () => new Promise((resolve, reject) => {
      console.log("안녕ssssss");
      	setTimeout(() => {
        console.log("안녕");
        resolve('❤');
        }, 1000);
      })
  • 이 코드는 getHen에 메서드를 정의한 것이다. 메서드를 호출해야 Promise가 생성된다
let promise = new Promise(function(resolve, reject) {
  // executor 부분
});
  • 이 코드는 promise에 Promise object를 직접 생성해서 할당한 것이므로 저 코드를 만나자 마자 promise가 실행된다

비동기처리방식의 예시

function getData() {
	var tableData;
	$.get('https://domain.com/products/1', function(response) {
		tableData = response;
	});
	return tableData;
}

console.log(getData()); // undefined
  • get은 비동기처리를하는 함수이다. 그렇기때문에 저 코드를 만나면 요청이 올때까지 기다리고 그동안 그 다음코드를 실행한다. tableData에는 할당받은 데이터가 저장되기 전이므로 undefined가 출력된다

콜백함수 예시

앞서 말한 js 비동기처리방식의 문제를 해결하였다

function getData(callbackFunc) {
	$.get('https://domain.com/products/1', function(response) {
		callbackFunc(response); // 서버에서 받은 데이터 response를 callbackFunc() 함수에 넘겨줌
	});
}

getData(function(tableData) {
	console.log(tableData); // $.get()의 response 값이 tableData에 전달됨
});

콜백지옥을 해결해보자!

$.get('url', function(response) {
	parseValue(response, function(id) {
		auth(id, function(result) {
			display(result, function(text) {
				console.log(text);
			});
		});
	});
});
function parseValueDone(id) {
	auth(id, authDone);
}
function authDone(result) {
	display(result, displayDone);
}
function displayDone(text) {
	console.log(text);
}
$.get('url', function(response) {
	parseValue(response, parseValueDone);
});

출처
https://ko.javascript.info/promise-basics#ref-700
https://elvanov.com/2597
https://jcon.tistory.com/189
https://joshua1988.github.io/web-development/javascript/javascript-asynchronous-operation/

profile
안녕하세요!

0개의 댓글