이 글은 node의 이벤트 루프 메커니즘을 이해하는 데 도움이 됩니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.
프런트엔드 개발은 JavaScript와 분리될 수 없습니다. JavaScript는 웹 개발에 주로 사용되며 브라우저에서 구문 분석되고 실행되는 웹 프론트엔드 언어입니다. js의 역할은 프론트엔드 개발에만 국한되지 않고, 서버사이드 개발인 nodejs에도 사용될 수 있습니다. 이상과 야망을 가진 프런트엔드 사람으로서 시야를 넓히고 서버 측 개발 언어를 마스터하고 싶다면 nodejs가 매우 좋은 선택입니다.
관련 권장 사항: "nodejs Tutorial"
js 개발 방법을 마스터했으므로 노드를 시작하기 쉽고 npm 패키지 관리 도구도 개발 경험을 크게 향상시킵니다. Nodejs는 비동기 비차단 I/O 작업 방식으로 유명하며, 해당 처리 메커니즘을 이벤트 루프라고 합니다.
노드 이벤트 루프 메커니즘을 이해하면 노드의 이벤트 처리 방법과 비동기 이벤트의 실행 타이밍을 더 잘 이해할 수 있습니다. 이 기사에서는 주로 nodejs의 이벤트 루프 메커니즘을 설명하고 노드 후속 학습의 기초를 마련합니다.
앞서 언급한 것처럼 Javascript는 주로 웹 개발에 사용되는 웹 프런트엔드 언어로, 브라우저에서 구문 분석하고 실행하는 반면 node.js는 이를 기반으로 하는 JavaScript 실행 환경입니다. Chrome V8 엔진입니다. 따라서 nodejs는 언어, 라이브러리, 프레임워크가 아니라 js 런타임 환경입니다. 간단히 말해서 node는 js 코드를 구문 분석하고 실행할 수 있습니다. 과거에는 브라우저에서만 JS를 구문 분석하고 실행할 수 있었지만 이제는 브라우저 없이도 노드를 사용하여 JS를 완전히 실행할 수 있습니다.
node.js와 브라우저 js에는 많은 차이점이 있습니다. 예를 들어 브라우저의 js에는 ecmascript, BOM, DOM이 포함되어 있지만 nodejs의 js에는 BOM과 DOM이 없고 emcscript만 있습니다. 그리고 노드의 js 실행 환경은 파일 읽기 및 쓰기, 네트워크 서비스 구축, 네트워크 통신, http 서버 등과 같은 js용 서버 수준 작업 API를 제공합니다. 이러한 API의 대부분은 핵심 모듈에 패키지되어 있습니다. 또한 노드의 이벤트 루프 메커니즘은 브라우저 js의 이벤트 루프 메커니즘과 다릅니다.
모두가 이미 브라우저의 js 이벤트 루프에 대해 매우 명확하게 알고 있습니다. 비교를 위해 여기서 간단히 언급하겠습니다.
js가 실행되면 동기 작업과 비동기 작업은 각각 다른 실행 환경에 들어갑니다. 동기 작업은 메인 스레드, 즉 메인 실행 스택과 비동기 작업(ajax 요청, settimeout, setinterval, poromise.resolve() 등)에 들어갑니다. ) 작업 대기열을 입력합니다. 다양한 비동기 작업은 ajax 요청, settimeout, setinterval 등과 같은 다양한 작업 대기열로 푸시됩니다. 이러한 작업은 매크로 작업 대기열(매크로 작업)로 푸시되고 Promise 함수는 마이크로 작업 대기열( 마이크로 태스크). 전체적인 이벤트 루프 프로세스는 다음과 같습니다.
동기 코드가 실행되면 기본 실행 스택이 비워지고 준비 작업이 비동기 작업을 실행하기 시작합니다.
메인 스레드는 마이크로태스크 대기열이 비어 있는지 확인합니다. 비어 있지 않으면 대기열의 모든 마이크로태스크를 순회하여 실행하고 마이크로태스크 대기열을 지운 다음 매크로태스크 대기열을 확인합니다. 마이크로태스크 대기열이 비어 있으면 다음 단계로 바로 진행하세요.
메인 스레드는 매크로 작업 대기열을 순회하여 매크로 작업 대기열의 첫 번째 매크로 작업을 실행합니다. 실행 중에 매크로 작업이나 마이크로 작업을 발견하면 계속해서 해당 작업 대기열로 푸시합니다. 매크로 작업이 실행되면 마이크로 작업 대기열을 순회하고 비워야 합니다
렌더링 작업을 수행하고 뷰를 업데이트합니다
다음 이벤트 루프를 시작하고 두 작업 대기열이 지워질 때까지 위 단계를 반복합니다
영향을 더욱 심화시키기 위해 작은 예를 들어 다음 코드가 무엇을 출력하는지 살펴보겠습니다.
var le=Promise.resolve(2); console.log(le) console.log('3') Promise.resolve().then(()=>{ console.log('Promise1') setTimeout(()=>{ console.log('setTimeout2') },0) }) setTimeout(()=>{ console.log('setTimeout1') Promise.resolve().then(()=>{ console.log('Promise2') }) },0);
위의 이벤트 루프 프로세스를 사용하여 분석합니다.
그래서 출력 결과는 다음과 같습니다. : 약속 {
브라우저에서의 실행 결과는 다음과 같습니다.
노드의 이벤트 루프는 6단계로 이루어지며, 이 6단계는 다음 노드까지 순차적으로 실행됩니다. 이벤트 처리가 완료되었습니다. 6단계의 시퀀스 다이어그램은 다음과 같습니다.
六个阶段分别是:
事件循环中,每当进入某一个阶段,都会从该阶段对应的回调队列中取出函数去执行。当队列为空或者执行的回调函数数量到达系统设定的阈值,该阶段就会终止,然后检查NextTick队列和微任务队列,将其清空,之后进入下一个阶段。
这里面比较关键的是poll阶段:
同样的举个大大的,看看以下代码会输出什么:
console.log('start') setTimeout(() => { console.log('timer1') Promise.resolve().then(function() { console.log('promise1') }) }, 0) setTimeout(() => { console.log('timer2') Promise.resolve().then(function() { console.log('promise2') }) }, 0) Promise.resolve().then(function() { console.log('promise3') }) console.log('end')
利用node事件循环分析呗:
因此输出顺序是:start,end,promise3,timer1,promise1,timer2,promise2,如果能正确回答出来说明对node的循环机制有了大体的了解,实际node输出结果确实是这样:
那如下代码会输出什么呢?
process.nextTick(function(){ console.log(7); }); new Promise(function(resolve){ console.log(3); resolve(); console.log(4); }).then(function(){ console.log(5); }); process.nextTick(function(){ console.log(8); });
继续分析:
因此最终输出是:3,4,7,8,5,需要记住,process.nextTick 永远大于 promise.then的优先级
还有一个大家很容易混淆的点就是setTimout和setImmediate的执行时机,根据上面描述的node事件循环机制,setImmediate()应该在check阶段执行 与 而setTimeout在timer阶段执行,理论上setTimout比setImmediate先执行,看下面的代码:
setTimeout(() => console.log(1),0); setImmediate(() => console.log(2));
执行结果是什么?1,2 还是 2,1,其实都有可能,看实际node运行的结果:
可以看到两次执行的结果不一样,为什么呢?原因在于即使setTimeout的第二个参数默认为0,但实际上,Node做不到0秒就执行其回调,最少也要4毫秒。那么进入事件循环后,如果没到4毫秒,那么timers阶段就会被跳过,从而进入check阶段执行setImmediate回调,此时输出结果是:2,1;
如果进入事件循环后,超过4毫秒(只是个大概,具体值并不确定),setTimeout的回调会出现在timer阶段的队列里,回调将被执行,之后再进入poll阶段和check阶段,此时输出结果是:1,2
那如果两者在I/O周期内调用,谁先执行呢?看一下代码:
const fs = require('fs') fs.readFile('./test.txt', 'utf8' , (err, data) => { if (err) { console.error(err) return } setTimeout(() => { console.log('timeout'); }, 0); setImmediate(() => { console.log('immediate'); }); })
实际上,node中输出的结果总是immediate先输出,timeout后输出。因为I/O回调是在poll阶段执行,当回调执行完毕之后队列为空,发现存在setImmediate的回调就会进入check阶段,执行完毕后,再进入timer阶段。
本文结合代码示例,对node的事件循环机制做了比较详细描述。通过这篇文章,应该可以了解浏览器的事件循环机制是怎样的,node的循环机制是怎样的,以及nextTick和micro队列的优先级,setTimout和setImmediate执行时机等一些容易混淆的知识点。文章中不足和不对之处,欢迎在评论区交流讨论,一起探索,谢谢。
更多编程相关知识,请访问:编程入门!!
위 내용은 nodejs의 이벤트 루프 메커니즘에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!