Javascript 장시간 실행 작업 - CPU 사용 유휴 시간
일부 기술은 사용자 인터페이스를 파괴하는 것을 피할 수 있는데, 그 중에서 가장 흔히 볼 수 있는 것은 이런 임무를 웹 작업자에게 이전하는 것이다.이 글에서 나는 어떻게 일을 블록으로 분할하고 CPU의 여가 시간을 사용하여 그것들을 처리하는지 다른 방법을 연구할 것이다.React팀은 광섬유 구조에서 이런 기술을 사용했다. 트리의 조화를 중단하고 더 우선적인 업무를 하도록 함으로써 사용자의 perceived performance을 향상시킬 수 있다.
주의: 본고의 모든 내용은react광섬유 구조의 계발을 받았다(그러나 매우 간단한 방법을 사용했다).참고 자료 부분으로 넘어가면react의 작업 원리를 이해하는 데 도움을 줄 수 있는 자원을 얻을 수 있습니다.
테스트 용례
100000개의 노드를 포함하는 목록 중 이전 노드의 값에 따라 노드의 값을 계산합니다. 사용자가 첫 번째 노드를 변경할 때 이 체인의 각 노드를 다시 계산하고 9999개의 노드를 생성하여 차단 계산을 실행해야 합니다.
다음 인터페이스가 있는 노드:
interface INode {
id: string;
value: number | null;
previousId: string | null;
nextId: string | null;
}
노드 맵 만들기:const nodes = new Map<INode>();
nodes.set('A1', {
id: 'A1',
nextId: 'A2',
previousId: null,
value: 99
});
nodes.set('A2', {
id: 'A2',
nextId: 'A3',
previousId: 'A1',
value: null
});
...
nodes.set('A100000', {
id: 'A100000',
nextId: null,
previousId: 'A99999',
value: null
});
요구 사항
우리의 솔루션은 다음과 같은 요구 사항을 지원해야 합니다.
어떻게 우리 방법의 질을 평가합니까?
CPU 사용 유휴 시간
The window.requestIdleCallback() method queues a function to be called during a browser's idle periods. This enables developers to perform background and low priority work on the main event loop, without impacting latency-critical events such as animation and input response. Functions are generally called in first-in-first-out order; however, callbacks which have a timeout specified may be called out-of-order if necessary in order to run them before the timeout elapses.
requestIdleCallback을 호출하여 다음 CPU 유휴 기간을 조정합니다.이 리셋에서, 우리는
deadline.timeRemaining()
을 호출하여 여가 기간이 끝날 때까지 얼마나 남았는지 검사할 수 있다.유휴 시간의 최대치는 50ms이지만, 대부분의 경우 우리가 얻는 시간은 50ms보다 적다. 이것은 CPU의 바쁜 정도에 달려 있다.잉여 시간과 매번 계산된 고정 최대 시간을 사용하면 우리는 여유 시간이 있는지 다시 계산하거나 다음 여유 기간으로 재배치할 수 있다.우리는 더 많은 임무를 집행해야 할 때까지 새로운 소환을 안배할 것이다.이러한 방식으로 노드를 처리하면 관건적인 사건을 중단하지 않고 원활한 사용자 체험을 제공할 수 있습니다.
일을 안배하다
CPU의 여유 시간을 사용하고 있기 때문에 사용자는 언제든지 페이지와 상호작용하고 새로운 작업을 배정할 수 있습니다.이것은 우리가 일을 기다리는 대열을 보류해야 한다는 것을 의미한다.
주어진 노드를 처리하고 이 노드에 새로운 작업을 배정하고 있다면, 우리는 현재 작업을 중단하고 이 노드를 다시 대기열의 끝까지 밀어야 한다.
interface IUnitOfWork {
triggerNodeId: string;
node: INode;
}
let workQueue: INode[] = [];
let nextUnitOfWork: IUnitOfWork | null = null;
function scheduleWork(node: INode): void {
/**
* Verify if there is already a work being
* process that was triggered by the same node
*/
const isInProgress = nextUnitOfWork && nextUnitOfWork.triggerNodeId === node.id;
if (isInProgress) {
nextUnitOfWork = null;
}
workQueue.push(node);
requestIdleCallback(performWork);
}
우리의 방법은 CPU의 사용 가능한 시간을 바탕으로 하는 것이지만, 사용 가능한 시간이 한 단위의 일을 완성할 수 있다는 것을 어떻게 알 수 있습니까?응, 그건 과자야!현재 이 문제를 해결하는 방법은 우리가 통상적으로 모든 작업 단원을 처리하고 상수 ENOUGH_TIME
에 저장하는 데 필요한 중간 시간을 가정하는 것이다.이것은 조정이 필요할 것이다. 이것은 매우 구체적인 작업이 될 것이다. 너는 반드시 응용 프로그램에 있어야 한다.const ENOUGH_TIME = 2; // in ms
앞에서 본 바와 같이, 우리가 작업을 계획할 때, 우리는 requestIdleCallback
을 호출했고, 이것은 최종적으로 우리의 performWork
함수를 호출할 것이다.이 함수에서 우리는 workLoop
을 시작합니다.workLoop
에서 다음 작업 단원을 가져옵니다. 없으면 작업 대기열에서 새 노드를 선택하십시오.그리고while 순환에서 performUnitOfWork
함수를 호출하기 시작합니다. 우리가 한 점에 도달할 때까지, 우리는 더 많은 시간이 없거나 더 많은 작업 단원이 없다고 생각합니다.performUnitOfWork
은 각 노드를 처리하는 함수입니다. (이 함수는 상세하게 소개하지 않습니다. 이 예에서 주로 가상 계산이기 때문입니다.)workLoop
이 완성되면 performLoop
함수로 돌아갑니다. 작업 대기열에 next Unit OfWork나 노드가 남아 있다면, 새로운 빈 리셋을 설정하고 이 과정을 다시 시작합니다.function resetNextUnitOfWork() {
const node = workQueue.shift();
if (!node) return;
nextUnitOfWork = { triggerNodeId: node.id, node };
}
function workLoop(deadline: number): void {
if (!nextUnitOfWork) {
resetNextUnitOfWork();
}
while (nextUnitOfWork && deadline.timeRemaining() > ENOUGH_TIME) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
}
function performWork(deadline: number): void {
workLoop(deadline);
if (nextUnitOfWork || workQueue.length > 0) {
requestIdleCallback(performWork);
}
}
결과
블록 교체 방법의 실행 속도는 훨씬 빠르지만, 다음gif에서 보듯이 프레임을 버리는 경우가 많다.페이지가 한동안 응답하지 않을 것입니다.
유휴 리셋 방법은 CPU의 사용 빈도에 따라 예측할 수 없는 실행 시간을 필요로 하지만 페이지는 항상 응답성을 가지기 때문에 감지된 성능이 더 좋을 수 있습니다.
this video을 검사하여 본문을 작성할 때 작성한 예시의 출력 결과를 보십시오.
결론
이 단독 테스트에서 Request Idle Callback을 사용하는 방법은 우리의 요구를 검사한 것 같다.
만약 우리가 100개의 계산을 처리한다면, 여가 실행 시간은 일반적인 차단 조작과 차이가 크지 않지만, 만약 우리가 10만 개의 계산을 처리한다면, 여가 방법은 더욱 긴 시간을 들일 것이지만, 더욱 매끄러울 것이다.이것은 일종의 균형이다. 나 개인적으로 말하자면, 나는 이것이 가치가 있다고 생각한다.
하지만 주의해야 할 것은 browser support은 아직 이상적이지 않다는 것이다...IE Edge 또는 Safari는 지원되지 않습니다...항상 그 두 개 맞죠?😞 어떤 방법은 그것을 채울 수 있다. 예를 들어 이 간단한 gist과 react's approach은 더욱 복잡하고 건장한 방법이다.
그러나 몇 가지 주제는 더욱 연구해야 한다.
리소스
만약 당신이 어떤 잘못을 발견한다면, 나의 엉망진창인 영어든 기술적인 세부 사항이든 부끄러워하지 말고 저에게 트위터를 보내주세요.나는 이 박문을 끊임없이 개선하기 위해 노력할 것이다:simple_미소:
Reference
이 문제에 관하여(Javascript 장시간 실행 작업 - CPU 사용 유휴 시간), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/canastro/javascript-long-running-tasks-use-cpu-s-idle-periods-58g2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)