>웹 프론트엔드 >JS 튜토리얼 >Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사

Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사

青灯夜游
青灯夜游앞으로
2021-11-05 09:48:252374검색

이 기사는 Node.js의 이벤트 루프(타임 루프) 메커니즘을 이해하는 데 도움이 되기를 바랍니다.

Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사

오늘은 nodeJs의 이벤트 루프에 대해 알아 보겠습니다. 저에게는 항상 이벤트 루프에 대한 이해가 큰 어려움이었습니다. 이번 연구를 통해 이 어려움을 극복하고 또한 이 블로그를 통해 이벤트 루프에 대한 이해와 감동이 깊어졌으면 좋겠습니다.

libuv

이벤트 루프를 배우기 전에 먼저 노드의 libuv를 이해하세요. libuv는 다양한 운영 체제에서 다양한 I/O 모델의 구현을 담당하고 타사 애플리케이션과 함께 사용할 수 있는 API로 다양한 구현을 추상화합니다.

Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사

Question

이벤트루프를 정식으로 배우기에 앞서, 한 가지 질문을 생각해 봅시다

    setTimeout(() => {
      console.log("timer1");
      Promise.resolve().then(() => {
        console.log("promise1");
      });
    }, 0);

    setTimeout(() => {
      console.log("timer2");
      Promise.resolve().then(() => {
        console.log("promise2");
      });
    }, 0);

이 코드를 브라우저에서 실행하면 어떤 결과가 나올까요?

Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사

노드에서 실행한 결과는 무엇인가요? ㅋㅋㅋ

먼저 사진을 보겠습니다.

Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사사진에서 타이머, 보류 중인 콜백, 유휴/준비, 폴링, 확인, 콜백 닫기의 6단계를 볼 수 있습니다.

timers 단계: 주로 setTimeOut, setInterval 콜백 실행

Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사pending 콜백 단계: 네트워크 통신 오류 콜백과 같은 일부 시스템 호출 오류 실행

idle/prepare 단계: 시스템 내에서만 사용됩니다. 이 단계에서는 제어 및 간섭이 없습니다)

폴링 단계: 파일 읽기를 위한 I/O 콜백 가져오기와 같은 새로운 I/O 이벤트를 가져옵니다.

적절한 상황에서 nodejs는 이 단계에서 차단됩니다

Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사

check 단계: setImmediate 콜백 실행
  • 예를 들어 sokect의 destory 실행, 이벤트 콜백 종료
  • 각 단계는
  • FIFO
  • (

    First in First out

    ) 규칙에 따라 작업 대기열에 있는 작업을 실행합니다. 이 6가지 단계 중
  • timers, poll, check
  • 단계에 집중해야 합니다. 일상적인 개발에서 대부분의 비동기 작업은 이 세 단계에서 처리됩니다.

    timers

  • 먼저 타이머 단계에 대해 이야기해 보겠습니다.

    timers는 이벤트 루프의 첫 번째 단계입니다. nodejs는 만료된 타이머가 있는지 확인하고, 그렇다면 콜백을 대기열에 넣습니다. 그러나 nodejs는 미리 설정된 이벤트가 도착할 때 타이머가 즉시 콜백을 실행한다고 보장할 수 없습니다. 이는 nodejs의 타이머 만료 확인이 반드시 신뢰할 수 있는 것은 아니기 때문입니다. 현재 메인 스레드가 유휴 상태가 아닙니다.
  • 여기서 불확실성에 대해 공식 웹 사이트는 다음과 같은 예를 제공합니다.

    먼저 setTimeOut을 선언한 다음 외부에서 파일을 읽습니다. 파일 읽기 작업이 타이머를 초과하면 파일 읽기 작업이 서버의 콜백을 설정합니다. 앞서 언급한 것처럼 메인 스레드가 유휴 상태가 아닌 상황입니다.

poll

폴 단계는 주로 두 가지 작업을 수행합니다. 1. 폴 단계의 작업 대기열을 처리합니다. 2 타이머가 초과되면 콜백 기능을 실행합니다.

위 그림에서 다음도 볼 수 있습니다.

폴링 단계에서 폴링 작업 대기열의 작업을 실행한 후 사전 설정된 setImmediate가 있는지 확인하고, 없으면 확인 단계로 들어갑니다. 여기서 차단하겠습니다.
여기서 질문이 있습니다. 투표 단계에서 차단되면 우리가 설정한 타이머가 실행될 수 없는 것 아닌가요?
사실
이벤트 루프가 폴링 단계에서 차단되면 nodejs에는 타이머 큐가 비어 있는지 확인하는 메커니즘이 있습니다. 비어 있지 않으면 타이머 단계로 다시 들어갑니다.

check

체크 단계에서는 주로 setImmediate 콜백 함수를 실행합니다.

小总结

event-loop的每个阶段都有一个队列,当event-loop达到某个阶段之后,将执行这个阶段的任务队列,直到队列清空或者达到系统规定的最大回调限制之后,才会进入下一个阶段。当所有阶段都执行完成一次之后,称event-loop完成一个tick。

案例

上面我们说完了event-loop的理论部分,但是光有理论我们也还是不能很清晰的理解event-loop。下面我们就根据几个demo来更加深入的理解下event-loop!

demo1

    const fs=require('fs')
    fs.readFile('test.txt',()=>{
            console.log('readFile')
            setTimeout(()=>{
                    console.log('settimeout');
            },0)
            setImmediate(()=>{
                    console.log('setImmediate')
            })
    })

执行结果:

Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사

可见执行结果跟我们前面的分析时一致的!

demo2

    const fs = require("fs");
    const EventEmitter = require("events").EventEmitter;
    let pos = 0;
    const messenger = new EventEmitter();

    messenger.on("message", function (msg) {
      console.log(++pos + " message:" + msg); //
    });

    console.log(++pos + " first"); //

    process.nextTick(function () {
      console.log(++pos + " nextTick"); //
    });

    messenger.emit("message", "hello!");
    fs.stat(__filename, function () {
      console.log(++pos + " stat"); //
    });

    setTimeout(function () {
      console.log(++pos + " quick timer"); //
    }, 0);
    setTimeout(function () {
      console.log(++pos + " long timer"); //
    }, 30);
    setImmediate(function () {
      console.log(++pos + " immediate"); //
    });

    console.log(++pos + " last"); //

结果:

Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사

了解下浏览器和node的event-loop差异在什么地方

在node 8.6 之前:

浏览器中的微任务队列会在每个宏任务执行完成之后执行,而node中的微任务会在事件循环的各个阶段之间执行,即每个阶段执行完成之后会去执行微任务队列。

在8.6之后:

浏览器和node中微任务的执行是一致的!

所以,在文章开头,我们提出的思考的问题就有了结果。

关于 process.nextTick()和setImmediate

process.nextTick()

语法:process.nextTick(callback,agrs)

执行时机:

这个函数其实是独立于 Event Loop 之外的,它有一个自己的队列,当每个阶段完成后,如果存在 nextTick 队列,就会清空队列中的所有回调函数,并且优先于其他 microtask 执行。递归的调用process.nextTick()会导致I/O starving,官方推荐使用setImmediate()

关于starving现象的说明:

    const fs = require("fs");
    fs.readFile("test.txt", (err, msg) => {
      console.log("readFile");
    });

    let index = 0;

    function handler() {
      if (index >= 30) return;
      index++;
      console.log("nextTick" + index);
      process.nextTick(handler);
    }

    handler();

运行结果:

Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사

可以看到,等到nextTick函数呗执行30次之后,读取文件的回调才被执行!这样的现象被称为 I/O 饥饿

当我们把 process.nextTick 换为 setImmediate

    const fs = require("fs");
    fs.readFile("test.txt", (err, msg) => {
      console.log("readFile");
    });

    let index = 0;

    function handler() {
      if (index >= 30) return;
      index++;
      console.log("nextTick" + index);
      setImmediate(handler);
    }

    handler();

结果:

Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사

造成这两种差异的原因是,嵌套调用的setImmediate的回调被排到了下一次event-loop中去!

event-loop核心思维导图

1Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사

结束语

通过今天的学习,让我对event-loop的理解更深刻了。那么,下次见。好好学习,天天向上!

1Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사

更多编程相关知识,请访问:编程视频!!

위 내용은 Node.js의 이벤트 루프 메커니즘에 대해 설명하는 기사의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제