Promise와 async await

김호중·2023년 2월 13일
0

javascript

목록 보기
6/9

Promise

콜백함수에 대한 개념은 여기를 참고한다.
Promise에 대한 참고자료

- 콜백 지옥

비동기적으로 작업을 실행하기 위해 콜백함수를 활용하게 된다.

function firstFunc(a,b, inFunc) {
  setTimeout(() => {
    const result = a +b;
    inFunc(result);
  }, 2000);
}

firstFunc(5,5, (res) => console.log(res));
console.log("end");

하지만 이런 함수가 계속해서 중첩하게 된다면?
가독성이 최악인 코드가 생겨날 것이다.

function increase(number, callback) {
	setTimeout(() => {
		const result = number + 10;
		if (callback){
			callback(result);
		} 
	},1000)
}

increase(0, result => {
	console.log(result);
	increase(result, result => {
		console.log(result);
		increase(result, result => {
			console.log(result);
			console.log("작업 완료");
		});
	});
});

console.log("과연 마지막에 호출될까?");

이를 해결하기위해 Promise가 등장한다.

- promise의 구조

let promise = new Promise(function(resolve, reject) {
  // executor (제작 코드, '가수')
});

- 실행(executor)시, Promise의 상태변화

resolve와 reject 두가지 경우가 있다. 이는 자바스크립트가 제공하는 콜백함수이다. (따라서 개발자는 excutor만 작성하면 된다.)
둘 중 하나의 콜백함수는 무조건! 호출해야한다.

  • 실행전
    state: "pending"
    result: undefined
  • 실행후
    1. resolve(value)
      state: "fulfilled"
      result: value
    2. reject(error)
      state: "rejected"
      result: error

위에서 언급되는 promise객체 내부의 state, result는 직접 접근할 수 없다. .then, .catch, .finally 메서드들을 통해서만 접근 가능하다.

  • then
    결과(result = 이행 or 실패)를 받아 해당 결과에 따른 동작을 수행한다.
    .then(성공시 f, 실패시 f)
    성공했을 때 만을 수행하려면
    .then(f) 이와 같이 사용한다.
  • catch
    결과가 실패했을 때 사용한다.
    .catch(f)
  • finally
    결과와 상관 없이, 결과를 모르는 채로 동작한다. 이 다음 메서드에 결과를 그대로 전달한다.
    .finally(f).then(f)
    .finally(f).catch(f)

- promise 체이닝

  • 올바른 체이닝 예시
    하나의 promise에 연속적으로 then을 달아둠.
new Promise(function(resolve, reject) {

  setTimeout(() => resolve(1), 1000); // (*)

}).then(function(result) { // (**)

  alert(result); // 1
  return result * 2;

}).then(function(result) { // (***)

  alert(result); // 2
  return result * 2;

}).then(function(result) {

  alert(result); // 4
  return result * 2;

});
  • 잘못된 체이닝 예시
    하나의 promise에 독립적으로 여러개의 then을 달아둠.
let promise = new Promise(function(resolve, reject) {
  setTimeout(() => resolve(1), 1000);
});

promise.then(function(result) {
  alert(result); // 1
  return result * 2;
});

promise.then(function(result) {
  alert(result); // 1
  return result * 2;
});

promise.then(function(result) {
  alert(result); // 1
  return result * 2;
});

- 프라미스 API

promise API

- 프라미스화

function promisify(f) {
  return function (...args) { // 래퍼 함수를 반환함
    return new Promise((resolve, reject) => {
      
      function callback(err, result) { // f에 사용할 커스텀 콜백** = 헬퍼함수 느낌
        if (err) {
          reject(err);
        } else {
          resolve(result);
        }
      }

      args.push(callback); // 위에서 만든 커스텀 콜백을 함수 f의 인수 끝에 추가합니다.
		// 이렇게 추가하고 아래에서 진짜 실행
      f.call(this, ...args); // 기존 함수를 호출합니다. = 진짜 실행되는 부분!!!
    });
  };
};

// 사용법:
let loadScriptPromise = promisify(loadScript);
loadScriptPromise(...).then(...);

async await

- async

함수 앞에 붙이는 키워드. 아래 두가지 기능을 갖는다.
1. 항상 promise를 반환한다.
2. 함수 내에서 await을 사용할 수 있다.

- await

함수 내에서 await 키워드를 사용한다면, 해당 프라미스가 완료되기까지 함수의 실행을 잠심 멈춘다.

또한 await은 thenable한 객체를 return한다.

!주의!
최상위 코드에서 async/await을 사용할 수 없다.
그래서 이럴 땐 익명함수로 감싸서 사용해야한다.

(async () => {
  let response = await fetch('/article/promise-chaining/user.json');
  let user = await response.json();
  ...
})();
profile
개발의 흔적을 남기고 쌓아가기 위한 일기장

0개의 댓글