리액트의 비동기 처리
리액트의 비동기 처리 방식
import React from 'react';
const AsyncTest = () => {
const test1 = () => {
console.log("test1 함수")
}
const test2 = () => {
console.log("test2 함수")
}
const test3 = () => {
console.log("test3 함수")
}
const syncTest = () => {
test1();
test2();
test3();
}
return (
<div>
<button onClick={syncTest}>자바스크립트 동기방식 처리</button>
</div>
);
};
export default AsyncTest;
해당 코드는 지극히 평범한 자바 스크립트의 동기처리방식이다 (블로킹 방식)
하나의 쓰레드에서 순차적으로 동작을 처리한다. ex) test1() → test2() → test3()
하나의 작업이 모두 끝나야 다음 동작을 처리하기 때문에 시간이 오래걸린다.
자바 스크립트는 기본적으로 하나의 쓰레드만 사용하기 때문에 멀티 쓰레드로 작업을 처리할 수 없다. 그래서 여러 작업을 수행해야 하는 경우 비동기 통신으로 작업을 처리한다.
import React from 'react';
const AsyncTest2 = () => {
const test1 = (num1, num2, callbackfunc) => {
// setTimeout은 자바스크립트에서 제공되는 비동기 통신 함수
// setTimeout(콜백함수, 지연시간) 해당 시간이 초과되었을때 콜백함수를 실행시킨다
// 2초 후에 콜백함수를 실행시킨다
setTimeout(() => {
// 해당 작업을 수행한 뒤 콜백펑션을 작동시킨다
let result = num1 + num2;
callbackfunc(result);
console.log("테스트 1 작업");
}, 2000);
}
const callbackfunc = (result) => {
console.log("비동기통신의 실행결과 => ", result)
}
const asyncTest = () => {
test1(100, 200, callbackfunc);
console.log("작업 완료")
}
return (
<div>
<button onClick={asyncTest}>자바스크립트 비동기방식 처리</button>
</div>
);
};
export default AsyncTest2;
해당 방법은 asyncTest 함수를 작동시킨 후 test1 함수를 작동시키고 console.log를 출력한다.
하지만 test1함수는 2초가 지난 뒤 console.log를 출력하도록 설계되어있음으로 (작업완료 → 콜백펑션 → 테스트 1 작업) 순으로 작동한다.
자바 스크립트에는 자바와 비슷하게 Heap영역과 callStack 영역으로 나눠어져 있다.
callStack 영역은 사용자의 명령을 순차적으로 처리하는 영역으로 자바의 stack과 비슷한 개념인 것 같다.
여기서 setTimeout같은 비동기 동작을 명령할 경우 callback 펑션과 setTimeout을 포함한 해당 작업은 webAPI 영역으로 이동해 해당 작업을 보류해둔다.
여기서 callback 펑션은 call queue 영역에서 실행될것이며 Event Loop에 의해 작동하게 된다.
Event Loop 가 callStack 영역을 계속 탐색하며 동작할 작업이 없으면 Call Queue 영역에 할당되어 있는 callBack 펑션을 실행시킨다.
비동기 작업의 이동 순서를 정리하자면
CallStack → webAPI → Callback Queue → Event Loop로 CallStack 영역에 할당된 작업이 없는지 체크 → CallBack Queue에 할당된 CallBack 함수를 실행
이렇게 setTimeout() 펑션으로 비동기 통신작업을 수행할 수 있다.
- GPT의 추가 설명
- Call Stack (콜 스택):
- Call Stack은 함수 호출을 관리하는 영역으로, 스택(Stack) 자료구조의 형태를 가지고 있습니다. 함수를 호출하면 해당 함수의 실행 컨텍스트가 스택에 추가되고, 함수가 반환될 때 해당 컨텍스트가 스택에서 제거됩니다.
- Web API:
- setTimeout()과 같은 비동기 함수는 브라우저 환경에서 제공되는 Web API에 의해 처리됩니다. Web API에서는 비동기 작업이 수행되고, 작업이 완료되면 콜백 함수가 호출됩니다.
- Callback Queue (또는 Task Queue):
- 비동기 작업의 콜백 함수는 주로 Callback Queue (또는 Task Queue)에 들어가며, 콜백 함수들은 순서대로 대기합니다. 여기서 대기하는 것은 이벤트 처리나 네트워크 요청 완료 등의 작업을 의미합니다.
- Event Loop:
- Event Loop는 주로 Call Stack을 관찰하고, Call Stack이 비어있을 때에만 Callback Queue에 있는 콜백 함수를 순서대로 실행합니다. 이를 통해 비동기 작업의 콜백 함수가 적절한 시점에 실행됩니다.
- 비동기 동작과 setTimeout():
- setTimeout() 함수를 사용하면 원하는 코드를 특정 시간 후에 실행할 수 있습니다. 이 코드는 비동기적으로 처리되며, 해당 코드 블록은 콜백 함수로 처리됩니다. 따라서 setTimeout()은 일정 시간이 지난 후에 콜백 함수를 Callback Queue에 추가하고, Event Loop가 이를 Call Stack으로 이동시켜 실행합니다.
- Call Stack (콜 스택):
- 제공하신 설명은 대체로 정확하게 이해하고 있으나 몇 가지 중요한 사항을 보완해야 합니다.
콜백함수
import React from 'react';
// test1, test2, test3
// test1의 실행결과를 test2가 사용
// test2의 실행결과를 test3이 사용
// test3 -> test2 -> test1
// 모두 콜백함수로 처리
const CallBackHellTest = () => {
const test1 = (num1, num2, callbackfunc) => {
setTimeout(() => {
let result = num1 + num2
callbackfunc(result)
}, 3000)
}
const test2 = (result, callbackfunc) => {
setTimeout(() => {
let test2_result = result*1000;
callbackfunc(test2_result) // 매개변수로 전달받은 test1의 결과를 콜백함수에 전달
}, 5000)
}
const test3 = (result, callbackfunc) => {
setTimeout(() => {
let test3_result = result/2;
callbackfunc(test3_result) // 매개변수로 전달받은 test2의 결과를 콜백함수에 전달
}, 2000)
}
const run = () => {
// 콜백지옥 시작
test1(1000,2000,(a_result) => {
console.log("A가 실행되고 실행결과를 B에 넘겨주기 ", a_result);
test2(a_result, (b_result) => {
console.log("B가 실행되고 실행결과를 C에 넘겨주기", b_result)
test3(b_result, (c_result) => {
console.log("C가 실행", c_result)
})
})
})
}
return (
<div>
<button onClick={run}>콜백 지옥</button>
</div>
);
};
export default CallBackHellTest;
import React from 'react';
const PromiseExam = () => {
const test1 = (num1, num2) => {
const run1 = (resolve,reject) => {
setTimeout(() => {
let result = num1 + num2
resolve(result)
}, 3000)
}
const obj = new Promise(run1)
return obj
}
const test2 = (result) => {
return new Promise((resolve,reject) => {
setTimeout(() => {
let test2_result = result*1000;
resolve(test2_result) // 매개변수로 전달받은 test1의 결과를 콜백함수에 전달
}, 5000)
})
}
const test3 = (result) => {
const run3 = (resolve,reject) => {
setTimeout(() => {
let test3_result = result/2;
resolve(test3_result) // 매개변수로 전달받은 test2의 결과를 콜백함수에 전달
}, 2000)
}
const asyncObj3 = new Promise(run3)
return asyncObj3
}
const run = () => {
test1(1000,2000)
.then((a_result) => {
console.log("test1이 실행되고 실행결과를 test2에 넘겨주기 ", a_result)
return test2(a_result)
})
.then((b_result) => {
console.log("test2이 실행되고 실행결과를 test3에 넘겨주기 ", b_result)
return test3(b_result)
})
.then((c_result) => {
console.log("test3이 실행", c_result)
})
}
return (
<div>
<button onClick={run}> 프로미스 </button>
</div>
);
};
export default PromiseExam;
비동기 통신의 종류로는 콜백함수를 사용하는 방법과 Promise 객체에 담아 리턴하는 방법이 있다.