IT/React
React 웹캠 - 1. Promise 비동기 함수의 이해
루벤초이
2021. 3. 29. 20:48
React 웹캠 시리즈입니다.
- React 웹캠 - 1. Promise 비동기 함수의 이해
- React 웹캠 - 2. getUserMedia
- React 웹캠 - 3. Canvas
- React 웹캠 - 4. Select webcam
웹캠 사용 코드는 React뿐만 아니라 일반 자바스크립트에서도 사용할 수 있는 코드인데요,
다만 이번 예제에서 React 앱을 연동하기 위해 React state/ref 등을 사용합니다.
예제 코드: Sample Code
실행 방법: npm start 후 브라우저에서 http://localhost:3000/test03 으로 접속
소스 위치: src/ui/TestWebcam.js
본격적으로 웹캠 코드를 논하기 전에, 자바스크립트의 비동기 작업의 미래 결과인 Promise에 대해 이해할 필요가 있습니다.
웹캠 코드가 비동기 함수, 즉 함수를 호출하는 즉시 리턴하고 결과는 나중에 알려주는 함수이기 때문입니다.
Promise, 비동기 작업의 미래 결과
- Promise 의미를 이해하기 보다는, 사용법을 익히는 편이 낫습니다.
- 아래 일반적인 Promise 코드 예제가 있는데요, go() 함수의 Line 1~5은 myPromise라는 Promise 객체를 생성한 것이고 나머지 라인은 생성된 myPromise 객체를 실행하는 부분입니다. 여기서 기계적으로 외워야 할 부분은 resolve(m)를 호출해야만 .then(m)이 호출된다는 사실입니다.
<html>
<script>
function go(){
let myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Success!");
}, 1000);
});
myPromise.then((message) => {
document.getElementById('result').innerHTML += '<p>2. Then : ' + message+'</p>';
});
document.getElementById("result").innerHTML += '<p>1. Finished</p>';
}
</script>
<body onload='go();'>
<div id="result"></div>
</body>
<html>
- 즉, 위 코드를 html 파일로 저장하고 브라우저에서 열면, 다음과 같이 "1. Finished"가 찍히고 1초 후에 "2. Then : Success!"가 찍힙니다.
- 원리는, html 파일이 로딩되면 body의 onload 함수로 지정된 go()가 불리고,
- 함수의 Line 7에서 myPromise의 setTimeout을 실행한 뒤 .then 절을 무시하고 Line 11의 "1. Finished"가 찍힙니다.
- 1000ms(1초) 후 setTimeout이 expired됨에 따라 setTimeout 함수 안에 있던 resolve가 불리면 그때, then() 안의 코드가 불리면서 "2. Then: Success!"가 찍히게 됩니다.
Promise + async/await, 비동기에서 동기로
- 만일 setTimeout처럼 콜백을 호출하는 비동기 함수를 여러번 중첩해서 쓰게 되면, 이른바 콜백지옥에 빠질 수 있습니다.
func1(() => {
func2(() => {
func3(()=>{
func4(()=>{
console.log("welcome to callback hell");
})
})
})
})
- 이런 구조가 깊어질수록 가독성이 떨어지고 버그가 많이 생기겠죠.
- 해결방안은 비동기 함수를 동기 함수, 즉 바로 결과를 리턴하는 함수로 만드는 방법입니다. 다시 말해, 결과를 리턴할 때까지 기다리는 거죠.
- 문법은 Promise 객체 앞에 await 키워드를 붙이고 현재 함수에 async 키워드를 붙이는 것인데, 아래 코드를 보고 형식을 외워버립시다.
<html>
<script>
async function go(){
let myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Success!");
}, 1000);
});
const message = await myPromise;
document.getElementById('result').innerHTML += '<p>2. Then : ' + message+'</p>';
document.getElementById("result").innerHTML += '<p>1. Finished</p>';
}
</script>
<body onload='go();'>
<div id="result"></div>
</body>
<html>
- 결과가 예상되나요?
- 그렇습니다. 이번엔 결과가 2, 1 순으로 나오죠. 왜냐하면 Line 7에서 await으로 기다렸다가 메시지2부터 찍고 난 다음 메시지1을 찍었기 때문입니다.
- 주의할 점은 go() 정의에 async 키워드가 붙어있는 점인데, 이를 람다 형식으로 정의할 때는 다음과 같이 정의합니다.
- const go = async() => {
Promise.all(), 모두 기다리기
- 마지막으로 살펴볼 것은 여러 Promise 객체를 동시 다발적으로 수행할 때 모든 작업이 완료되기를 기다리는 구문입니다.
- 예제 코드를 살펴봅시다.
<html>
<script>
async function go(){
let myPromise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Success!");
}, 1000);
});
let myPromise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Again!");
}, 3000);
});
Promise.all([myPromise1, myPromise2]).then((messageArray)=>{
document.getElementById('result').innerHTML += '['+messageArray[0]+', '+ messageArray[1]+']';
});
document.getElementById("result").innerHTML += '<p>1. Finished</p>';
}
</script>
<body onload='go();'>
<div id="result"></div>
</body>
<html>
- myPromise1, myPromise2 두 개의 객체가 있을 때 이 두 Promise가 모두 종료되고 나서 진행하겠다는 의미로 .then 대신 .all() 함수를 사용합니다. 이때 전달되는 값은 각 Promise의 resolve 결과값들의 배열입니다.
- 한 번 따라서 타이핑해보고 실행해 보면 이해도 하기 전에 익숙해질 거에요.
- 다음 시간에는 웹캠에 접근하는 getUserMedia에 대해 알아봅시다.
728x90
반응형