이 기사는 JavaScript 이벤트 루프 메커니즘에 대한 관련 지식 포인트를 공유합니다. 관심 있는 친구는 이를 배우고 참조할 수 있습니다.
우리 모두 알고 있듯이 JavaScript는 단일 스레드 언어입니다. Web-Worker는 html5에서 제안되었지만 이것이 단일 스레드인 JavaScript의 핵심을 바꾸지는 않습니다. HTML 사양에서 다음 구절을 참조하세요.
이벤트, 사용자 상호 작용, 스크립트, 렌더링, 네트워킹 등을 조정하려면 사용자 에이전트는 이 섹션에 설명된 대로 이벤트 루프를 사용해야 합니다.
이벤트, 사용자 상호 작용, 스크립트, UI 렌더링 및 네트워크 처리를 조정하려면 사용자 엔진이 이벤트 루프를 사용해야 합니다. 이벤트 루프는 두 가지 유형으로 구성됩니다. 하나는 브라우징 컨텍스트 기반이고 다른 하나는 작업자 기반이며, 둘 다 독립적으로 실행됩니다. 다음 문서에서는 예제를 사용하여 검색 컨텍스트를 기반으로 하는 이벤트 루프 메커니즘에 중점을 둡니다.
다음 JavaScript 코드를 보세요:
console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0); Promise.resolve().then(function() { console.log('promise1'); }).then(function() { console.log('promise2'); }); console.log('script end');
먼저 이 코드의 출력 순서를 추측한 다음 브라우저 콘솔에 입력하여 실제 출력 순서가 추측한 순서와 일치하는지 확인합니다. JavaScript 이벤트 루프 메커니즘에 대해 어느 정도 이해하고 있어야 합니다. 지식을 통합하기 위해 계속 읽으세요. 실제 출력 순서가 추측과 일치하지 않으면 이 문서의 다음 부분이 질문에 답하는 데 도움이 될 것입니다.
작업 대기열
모든 작업은 동기 작업과 비동기 작업으로 나눌 수 있습니다. 이름에서 알 수 있듯이 동기 작업은 일반적으로 실행을 위해 메인 스레드에 직접 들어가는 작업입니다. ajax 네트워크 요청, setTimeout 타이밍 기능 등과 같은 비동기적으로 실행되는 작업은 모두 비동기 작업이며 비동기 작업은 작업 대기열(이벤트 대기열) 메커니즘을 통해 조정됩니다. 구체적으로 다음 그림을 사용하여 대략적으로 설명할 수 있습니다.
동기 작업과 비동기 작업은 각각 다른 실행 환경에 들어갑니다. 동기 작업은 메인 스레드, 즉 기본 실행 스택에 들어가고 비동기 작업은 이벤트에 들어갑니다. 대기줄. 실행 후 메인 스레드의 작업이 비어 있으면 해당 작업이 이벤트 큐에서 읽혀지고 실행을 위해 메인 스레드로 푸시됩니다. 위의 과정이 지속적으로 반복되는 것을 우리는 이벤트 루프(Event Loop)라고 부릅니다.
이벤트 루프에서는 각 루프 작업을 틱이라고 합니다. 사양을 읽어 보면 각 틱의 작업 처리 모델이 상대적으로 복잡하다는 것을 알 수 있습니다. 주요 단계는 다음과 같이 요약할 수 있습니다. check 큐에 먼저 들어가는 태스크(가장 오래된 태스크)를 선택하고, 있으면 실행(1회)
마이크로태스크가 있는지 확인하고, 있으면 마이크로태스크 큐가 지워질 때까지 계속 실행
렌더링 업데이트
메인 스레드는 위 단계를 반복합니다
(매크로) 작업에는 주로 스크립트(전체 코드), setTimeout, setInterval, I/O, UI 대화형 이벤트, setImmediate(Node.js 환경)가 포함됩니다.
microtask에는 주로 Promise, MutaionObserver, process.nextTick(Node.js)이 포함됩니다. Node.js 환경)
setTimeout/Promise 및 기타 API는 작업 소스이며 작업 대기열에 들어가는 것은 이들이 지정한 특정 실행 작업입니다. 다양한 작업 소스의 작업은 서로 다른 작업 대기열에 들어갑니다. 그 중 setTimeout과 setInterval은 출처가 동일합니다.
샘플 코드 분석 수천 단어가 있으므로 예를 들어 명확하게 설명하는 것이 좋습니다. 아래에서는 사양을 따르고 위의 예제를 단계별로 분석할 수 있습니다. 먼저 예제 코드를 게시하여 위로 스크롤하지 않도록 하세요. console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
전체 스크립트는 첫 번째 매크로 작업으로 메인 스레드에 들어가 console.log를 만나고 출력 스크립트 start
가 setTimeout을 만나고 해당 콜백 함수가 매크로 작업 Event Queue
에 배포되어 Promise를 만나게 됩니다. then 함수는 마이크로태스크 이벤트 큐에 할당되어 then1로 기록되고, then 함수는 다시 발생하여 마이크로태스크 이벤트 큐에 할당되어 then2
console.log를 만나면 출력 스크립트 end
이 시점에서 이벤트 큐에는 다음 표에 표시된 대로 세 가지 작업이 있습니다.
- | |
so,你猜对了吗? 看看你掌握了没 再来一个题目,来做个练习: console.log('script start'); setTimeout(function() { console.log('timeout1'); }, 10); new Promise(resolve => { console.log('promise1'); resolve(); setTimeout(() => console.log('timeout2'), 10); }).then(function() { console.log('then1') }) console.log('script end'); 这个题目就稍微有点复杂了,我们再分析下: 首先,事件循环从宏任务 (macrotask) 队列开始,最初始,宏任务队列中,只有一个 scrip t(整体代码)任务;当遇到任务源 (task source) 时,则会先分发任务到对应的任务队列中去。所以,就和上面例子类似,首先遇到了console.log,输出 script start; 接着往下走,遇到 setTimeout 任务源,将其分发到任务队列中去,记为 timeout1; 接着遇到 promise,new promise 中的代码立即执行,输出 promise1, 然后执行 resolve ,遇到 setTimeout ,将其分发到任务队列中去,记为 timemout2, 将其 then 分发到微任务队列中去,记为 then1; 接着遇到 console.log 代码,直接输出 script end 接着检查微任务队列,发现有个 then1 微任务,执行,输出then1 再检查微任务队列,发现已经清空,则开始检查宏任务队列,执行 timeout1,输出 timeout1; 接着执行 timeout2,输出 timeout2 至此,所有的都队列都已清空,执行完毕。其输出的顺序依次是:script start, promise1, script end, then1, timeout1, timeout2 用流程图看更清晰: 总结 有个小 tip:从规范来看,microtask 优先于 task 执行,所以如果有需要优先执行的逻辑,放入microtask 队列会比 task 更早的被执行。 最后的最后,记住,JavaScript 是一门单线程语言,异步操作都是放到事件循环队列里面,等待主执行栈来执行的,并没有专门的异步执行线程。 以上就是本章的全部内容,更多相关教程请访问JavaScript视频教程! |
위 내용은 JavaScript 이벤트 루프 메커니즘에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!