JavaScript 비동기 처리 - Promise 객체

bp.chys·2020년 5월 19일
1
post-thumbnail
post-custom-banner

velopert님의 모던 자바스크립트 강의자료를 참고하여 작성했습니다.

자바스크립트는 동기식인가 비동기식인가?

우선 프로그래밍에서 동기(sync)와 비동기(async)의 정의를 이해할 필요가 있다.

동기 : 이전 작업의 실행이 끝나야 다음 작업 실행을 시작한다.
비동기 : 이전 작업의 실행과 무관하게 다음 작업을 실행한다.

동기와 비동기를 설명할 때 대표적인 예시로 은행과, 카페를 예시로 들곤한다. 은행에서는 사람들에게 번호표를 나눠주고, 이전 사람의 은행 일이 끝날 때 까지는 계속 대기해야 한다. 반면에 카페에서는 주문과 함게 진동벨을 받게 되고 진동벨이 울리기 전에 대기하면서 개인 작업을 할 수 있다.

싱글스레드인 자바스크립트는 기본적으로 동기식이지만, API에 요청을 보낼 때 응답이 올 때까지 마냥 기다리기만 할 수 없기 때문에 비동기 처리가 필요하다.

하지만 비동기 처리를 할 경우, 의도하지 않은 순서로 함수가 실행될 수 있기 때문에 원하는 부분에서 동기 방식으로 변환을 해줘야 한다.

첫번째 방식이 지난번에 살펴본 콜백함수이다. 콜백함수는 함수안에서 또 다른 함수를 호출하는 것인데 여러 함수를 순서대로 호출할 필요가 있을 경우 콜백지옥을 경험하게 되는 문제점이 있다.

숫자 n 을 파라미터로 받아와서 다섯번에 걸쳐 1초마다 1씩 더해서 출력하는 작업을 setTimeout 으로 구현해보자.

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에 대해 알아보자.

Promise

Promise는 성공할 수도 있고, 실패할 수 도 있다. 성공할 때는 resolve 함수를 호출하고, 실패할때는 reject 함수를 호출한다.

const myPromise = new Promise((resolve, reject) => {
  // 구현..
})

1초 뒤 성공하는 상황을 구현해 보자

const myPromise = new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve(1);
	}, 1000);
});

myPromise.then(n => {
	console.log(n);
});

resolve 를 호출 할 때 특정 값을 파라미터로 넣어주면, 이 값을 작업이 끝나고 나서 사용 할 수 있다. 작업이 끝나고 나서 또 다른 작업을 해야 할 때에는 Promise 뒤에 .then(...) 을 붙여서 사용하면 된다.

이번에는 1초뒤 실패하는 상황을 만들어보자

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(new Error());
  }, 1000);
});

myPromise
  .then(n => {
    console.log(n);
  })
  .catch(error => {
    console.log(error);
  });

실패하는 상황에서는 reject를 사용하고 .catch를 통하여 실패했을시 수행할 작업을 설정할 수 있다.

이제 Promise를 만드는 함수를 작성해 보자.

function increaseAndPrint(n) {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			const value = n + 1;
			if (value === 5) {
				const error = new Error();
				error.name = 'ValueIsFiveError';
				reject(error);
				return;
			console.log(value);
			resolve(value);
		}, 1000);
	});
}

increaseAndPrint(0)
	.then(increaseAndPrint)
	.then(increaseAndPrint)
	.then(increaseAndPrint)
	.then(increaseAndPrint)
	.then(increaseAndPrint)
	.catch(e => {
		console.error(e);
	});

Promise 를 사용하면, 비동기 작업의 개수가 많아져도 코드의 깊이가 깊어지지 않게 된다.

promise 좀 더 알아보기

프로미스 객체는 생성자를 사용해서 만들 수 있다.
생성자의 인자로 executor라는 함수를 이용한다.

new Promise( /*executor*/ );

executor함수는 resolve와 reject를 인자로 가진다.
(resolve, reject) ⇒ {...}
여기서 resolve와 reject는 각각 함수이다.

new Promise( /*executor*/ (resolve, reject) => {...} );

생성자를 통해 프로미스 객체를 만드는 순간 pending(대기) 상태라고 한다.

new Promise((resolve, reject) => {}); // pending

executor함수 인자중 하나인 resolve함수를 실행하면, fulfilled(이행) 상태가 된다.

new Promise((resolve, reject) => {
	//pending
	//... 비동기 처리
	resolve();  // fulfilled
});

executor함수 인자중 하나인 reject함수를 실행하면, rejected(거부) 상태가 된다.

new Promise((resolve, reject) => {
	reject();  // rejected
});

p라는 프로미스 객체는 1초 후에 fulfilled된다.
또한 fulfilled된 시점에 p.then안에 설정한 callback함수가 실행된다.

const p = new Promise((resolve, reject) => {
	/*pending*/
	setTimeout(() => {
		resolve(); /* fulfilled */
	}, 1000);
});

p.then(() => {
	/* resolve 된 이후에 실행됨*/ 
	/* callback */
	console.log('1000ms후에 fulfilled 됩니다.');
});

then을 설정하는 시점을 명확히하고 함수의 실행과 동시에 프로미스 객체를 만들면서 pending이 시작하도록 하기 위해 프로미스 객체를 생성하면서 리턴하는 함수 p를 만들어 p실행과 동시에 then을 설정한다.

function p() {
	return new Promise((resolve, reject) => {
		/*pending*/
		setTimeout(() => {
			resolve(); /* fulfilled */
		}, 1000);
	});
}

//원하는 시점에 프로미스 객체를 생성하고 콜백함수도 호출할 수 있다.
p().then(() => {
	console.log('1000ms후에 fulfilled 됩니다.');
});

이번엔 reject상황도 만들어보자. reject는 then이라니라 catch를통해 콜백함수를 처리한다.

function p() {
	return new Promise((resolve, reject) => {
		/*pending*/
		setTimeout(() => {
			reject(); /* rejected */
		}, 1000);
	});
}

//원하는 시점에 프로미스 객체를 생성하고 콜백함수도 호출할 수 있다.
p()
	.then(() => {
		console.log('1000ms후에 fulfilled 됩니다.');
	})
	.catch(() => {
		console.log('1000ms후에 rejected 됩니다.');
});

excecutor의 resolve함수에 인자를 넣어 실행하면, then의 callback함수의 인자로도 받을 수가 있다.

function p() {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve('hello'); 
		}, 1000);
	});
}

//원하는 시점에 프로미스 객체를 생성하고 콜백함수도 호출할 수 있다.
p().then(message => {
	console.log('1000ms후에 fulfilled 됩니다.', message);
});

마찬가지로 excecutor의 reject함수에 인자를 넣어 실행하면, catch의 callback함수의 인자로도 받을 수가 있다.

function p() {
	return new Promise((resolve, reject) => {
		/*pending*/
		setTimeout(() => {
			reject('error');
		}, 1000);
	});
}

//원하는 시점에 프로미스 객체를 생성하고 콜백함수도 호출할 수 있다.
p()
	.then(() => {
		console.log('1000ms후에 fulfilled 됩니다.');
	})
	.catch(reason => {
		console.log('1000ms후에 rejected 됩니다.', reason);
});

하지만 일반적으로는 error 문자열이 대신에 객체를만들어서 던진다.

function p() {
	return new Promise((resolve, reject) => {
		/*pending*/
		setTimeout(() => {
			reject(new Error('error');
		}, 1000);
	});
}

//원하는 시점에 프로미스 객체를 생성하고 콜백함수도 호출할 수 있다.
p()
	.then(() => {
		console.log('1000ms후에 fulfilled 됩니다.');
	})
	.catch(e => {
		console.log('1000ms후에 rejected 됩니다.', e);
	});

추가적으로 fulfilled 되거나 rejected된 후에 최종적으로 실행할 것이 있다면, .finally()를 설정하고, 함수를 인자로 넣는다.

function p() {
	return new Promise((resolve, reject) => {
		/*pending*/
		setTimeout(() => {
			reject(new Error('error');
		}, 1000);
	});
}

//원하는 시점에 프로미스 객체를 생성하고 콜백함수도 호출할 수 있다.
p()
	.then(() => {
		console.log('1000ms후에 fulfilled 됩니다.');
	})
	.catch(e => {
		console.log('1000ms후에 rejected 됩니다.', e);
	})
	.finally(() => {
		console.log('end');
	});

하지만, 이것도 불편한점이 있긴 하다. 에러를 잡을 때 몇번째에서 발생했는지 알아내기도 어렵고 특정 조건에 따라 분기를 나누는 작업도 어렵고, 특정 값을 공유해가면서 작업을 처리하기도 까다로운데 async/await 을 사용하면, 이러한 문제점을 깔끔하게 해결 할 수 있다.


참고자료

Async to sync Javascript

profile
하루에 한걸음씩, 꾸준히
post-custom-banner

3개의 댓글

comment-user-thumbnail
2024년 7월 22일

留学生作业代写 http://www.emwchinese.com/store 要想确保高质量,必须在任务理解与沟通、研究与资料收集、写作与结构安排、引用与参考文献以及审校与修改等方面下足功夫。通过充分的沟通、扎实的研究、科学合理的写作结构、正确规范的引用和全面细致的审校,代写者能够确保作业的学术价值和实际意义,满足客户的期望和学术标准,最终获得满意的分数。未来,随着学术要求的不断提升和代写市场的规范化,代写服务还需不断提升自身的专业水平和服务质量,才能在激烈的市场竞争中持续保持领先地位。

답글 달기
comment-user-thumbnail
2024년 9월 8일

Very educational post! This resource has a wealth of knowledge that can assist any business in launching an effective social media campaign. https://www.gurgaonfairy.com/

답글 달기
comment-user-thumbnail
2024년 9월 27일

I am quite sure I'll learn plenty of new stuff right here!

https://roshnikhanna.home.blog/2024/08/24/8-sexual-massage-types-that-will-create-intense-lust-in-your-partner/ |
https://www.diigo.com/item/note/b4wjx/yjc8?k=2228fa57ed55361b337a3ca0b07c8e47 |
https://roshnikhannaa.wordpress.com/2024/08/24/beat-boredom-and-exhaustion-with-an-erotic-massage/ |
https://www.linkedin.com/pulse/how-gurgaon-companion-can-help-during-business-trip-roshnikhanna-8ixec/ |
https://ameblo.jp/roshanikhanna/entry-12865429925.html |
https://roshanikhanna.amebaownd.com/posts/55122566 |
https://issuu.com/roshnikhanna/docs/escort_agency_in_gurgaon.docx/s/56866193 |
https://pad.fs.lmu.de/s/DsN7tTJLd |
https://roshanikhanna.thezenweb.com/planning-to-hire-gurgaon-escorts-here-is-all-you-need-to-know-67754640 |
https://myheritage.heritage.edu/ICS/Academics/RDG/RDG__502/1920_SU-RDG__502-10/Blog_3.jnz?portlet=Blog_3&screen=View+Post&screenType=next&&Id=7b05ada2-aa53-4698-94ac-11dfb206dfd2 |
https://www.storeboard.com/blogs/personal/meet-gurgaon-escorts-to-find-long-lasting-happiness-and-love/5818745 |
https://roshnikhanna.hashnode.dev/vip-escort-service-in-gurugram-with-hot-girls |
https://devayani.mystrikingly.com/ |
https://devayanikappor.blogspot.com/2024/07/benefits-of-meeting-escorts-regularly.html |
https://justpaste.it/Escort-Service-in-Gurgaon |
https://www.timessquarereporter.com/news/find-your-choice-of-girl-in-gurgaon |
https://bresdel.com/blogs/597422/Get-Luxury-Escorts-Service-in-Gurgaon-at-Affordable-Prices#google_vignette |
https://sites.google.com/view/female-escorts-in-gurugram/ |
https://sites.google.com/view/roshni-khanna/home |
https://roshni-khanna.mystrikingly.com/ |
https://roshni-khanna.blogspot.com/2024/08/full-body-sensual-massage-fbsm.html |
https://ai.ceo/read-blog/171214_erotic-sensual-body-massage-in-gurgaon.html |
https://docs.google.com/forms/d/1KYgpdpLrfkvrGfnt9BtcXXpKuomKceMo7TIOzSGeBYE/viewform?edit_requested=true |
https://roshnikhanna.medium.com/erotic-massage-in-gurgaon-27b79bb73b66

답글 달기