당신은 노드를 모른다

업데이트 :이 기사는 이제 내 책“Node.js Beyond The Basics”의 일부입니다.
이 컨텐츠의 업데이트 된 버전과 jscomplete.com/node-beyond-basics에서 노드에 대한 자세한 내용을 읽으십시오.

올해의 Forward.js 컨퍼런스 (JavaScript)에서는“노드를 모른다”라는 제목의 강연을했습니다. 이 강연에서 Nodejs 런타임에 대한 일련의 질문으로 청중에게 도전했으며 대부분의 기술 청중은 대부분의 질문에 대답 할 수 없었습니다.

나는 그것을 실제로 측정하지는 않았지만 확실히 그 방에서 그렇게 느껴졌고 몇 명의 용감한 사람들이 대화 후 나에게 다가 가서 사실에 고백했습니다.

여기 제가 그 이야기를하게 만든 문제가 있습니다. Node에게 올바른 방법을 가르치지 않는다고 생각합니다! Nodejs에 대한 대부분의 교육 내용은 런타임이 아닌 노드 패키지에 중점을 둡니다. 이러한 패키지의 대부분은 http 또는 스트림과 같은 Node 런타임 자체에서 모듈을 래핑합니다. 문제가 발생하면 이러한 문제가 런타임 자체에있을 수 있으며 Node 런타임을 모르면 문제가있는 것입니다.

문제 : Nodejs에 대한 대부분의 교육 내용은 런타임이 아닌 Node 패키지에 중점을 둡니다.

이 기사의 기능에 대한 몇 가지 질문과 답변을 선택했습니다. 아래에 헤더로 표시되어 있습니다. 먼저 머리에 대답하십시오!

여기에 잘못되거나 오도 된 답변이 있으면 알려주십시오.

질문 # 1 : Call Stack은 무엇이며 V8의 일부입니까?

콜 스택은 확실히 V8의 일부입니다. V8이 함수 호출을 추적하는 데 사용하는 데이터 구조입니다. 함수를 호출 할 때마다 V8은 해당 함수에 대한 참조를 호출 스택에 배치하고 다른 함수의 중첩 된 호출마다 계속 그렇게합니다. 여기에는 재귀 적으로 호출되는 함수도 포함됩니다.

Pluralsight 과정에서 캡처 한 스크린 샷 — Advanced Node.js

함수의 중첩 된 호출이 끝에 도달하면 V8은 한 번에 하나의 함수를 팝하고 대신 리턴 된 값을 사용합니다.

이것이 노드에 대해 이해해야하는 이유는 무엇입니까? 노드 당 하나의 호출 스택 프로세스 만 가져 오기 때문입니다. 해당 통화 스택을 사용 중 상태로 유지하면 전체 노드 프로세스가 사용 중입니다. 명심하십시오.

질문 # 2 : 이벤트 루프 란 무엇입니까? V8의 일부입니까?

이 다이어그램에서 이벤트 루프가 어디에 있다고 생각하십니까?

Pluralsight 과정에서 캡처 한 스크린 샷 — Advanced Node.js

이벤트 루프는 libuv 라이브러리에 의해 제공됩니다. V8의 일부가 아닙니다.

이벤트 루프는 외부 이벤트를 처리하고 콜백 호출로 변환하는 엔티티입니다. 이벤트 큐에서 이벤트를 선택하고 콜백을 콜 스택으로 푸시하는 루프입니다. 다상 루프이기도합니다.

이벤트 루프를 처음 듣는 경우에는 이러한 정의가 도움이되지 않습니다. 이벤트 루프는 훨씬 더 큰 그림의 일부입니다.

Pluralsight 과정에서 캡처 한 스크린 샷 — Advanced Node.js

이벤트 루프를 이해하려면 더 큰 그림을 이해해야합니다. V8의 역할을 이해하고 노드 API에 대해 알고 V8에 의해 큐가 실행되는 방법을 알아야합니다.

노드 API는 setTimeout 또는 fs.readFile과 같은 기능입니다. 이것들은 JavaScript 자체의 일부가 아닙니다. 그것들은 노드가 제공하는 기능 일뿐입니다.

Event Loop는이 그림의 중간에 위치하며 (실제로는 더 복잡한 버전) 주최자처럼 작동합니다. V8 호출 스택이 비어 있으면 이벤트 루프는 다음에 실행할 항목을 결정할 수 있습니다.

질문 # 3 : 호출 스택과 이벤트 루프 큐가 모두 비어있는 경우 노드는 어떻게합니까?

단순히 종료됩니다.

노드 프로그램을 실행하면 노드가 자동으로 이벤트 루프를 시작하고 해당 이벤트 루프가 유휴 상태이고 수행 할 다른 작업이 없으면 프로세스가 종료됩니다.

노드 프로세스를 계속 실행하려면 이벤트 큐에 무언가를 배치해야합니다. 예를 들어, 타이머 또는 HTTP 서버를 시작할 때 기본적으로 이벤트 루프에 계속 실행하고 이러한 이벤트를 확인하도록 지시합니다.

질문 # 4 : V8과 Libuv 외에 Node에 어떤 외부 종속성이 있습니까?

다음은 노드 프로세스가 사용할 수있는 별도의 라이브러리입니다.

  • http 파서
  • c-ares
  • OpenSSL
  • zlib

그들 모두는 노드 외부에 있습니다. 그들 자신의 소스 코드가 있습니다. 그들은 자신의 라이센스를 가지고 있습니다. 노드는 단지 그것들을 사용합니다.

프로그램이 어디에서 실행되고 있는지 알고 싶기 때문에 기억하고 싶습니다. 데이터 압축으로 무언가를 수행하는 경우 zlib 라이브러리 스택에서 문제가 발생할 수 있습니다. zlib 버그와 싸우고있을 수 있습니다. 노드의 모든 것을 비난하지 마십시오.

질문 # 5 : V8없이 노드 프로세스를 실행할 수 있습니까?

이것은 까다로운 질문 일 수 있습니다. 노드 프로세스를 실행하려면 VM이 필요하지만 V8 만 사용할 수있는 VM은 아닙니다. 차크라를 사용할 수 있습니다.

노드 차크라 프로젝트의 진행 상황을 추적하려면이 Github 저장소를 확인하십시오.

질문 # 6 : module.exports와 exports의 차이점은 무엇입니까?

언제든지 module.exports를 사용하여 모듈의 API를 내보낼 수 있습니다. 하나의 경우를 제외하고 내보내기를 사용할 수도 있습니다.

module.exports.g = ... // 좋아
exports.g = ... // 좋아
module.exports = ... // 좋아
exports = ... // 아님

왜?

exports는 module.exports에 대한 참조 또는 별명 일뿐입니다. 내보내기를 변경하면 해당 참조가 변경되고 공식 API (module.exports)는 더 이상 변경되지 않습니다. 모듈 범위에서 지역 변수를 얻습니다.

질문 # 7 : 어떻게 최상위 변수가 전역 적이 지 않습니까?

최상위 변수 g를 정의하는 module1이있는 경우 :

// module1.js
var g = 42;

그리고 module1이 필요한 module2가 있고 변수 g에 액세스하려고하면 g가 정의되지 않습니다.

왜? 브라우저에서 동일하게 수행하면 정의 후에 포함 된 모든 스크립트에서 최상위 정의 변수에 액세스 할 수 있습니다.

모든 노드 파일은 장면 뒤에서 자체 IIFE (즉시 호출 된 함수 표현식)를 얻습니다. 노드 파일에 선언 된 모든 변수는 해당 IIFE에 적용됩니다.

관련 질문 :이 한 줄만있는 다음 노드 파일을 실행하면 어떤 결과가 발생합니까?

// script.js
console.log (인수);

당신은 몇 가지 논쟁을 보게 될 것입니다!

왜?

Node가 실행 한 것은 함수이기 때문입니다. 노드는 코드를 함수로 감싸고 그 함수는 위에서 본 다섯 개의 인수를 명시 적으로 정의합니다.

질문 # 8 : 모든 파일에서 내보내기, 요구 및 모듈 개체를 모두 사용할 수 있지만 파일마다 다릅니다. 방법?

require 객체를 사용해야 할 때는 전역 변수 인 것처럼 직접 사용하면됩니다. 그러나 두 개의 다른 파일에서 require를 검사하면 두 개의 다른 객체가 표시됩니다. 방법?

같은 마술 IIFE로 인해 :

보시다시피 magic IIFE는 export, require, module, __filename 및 __dirname의 다섯 가지 인수를 코드에 전달합니다.

이 5 개의 변수는 노드에서 사용할 때 전역으로 보이지만 실제로는 함수 인수 일뿐입니다.

질문 # 9 : 노드에서 순환 모듈 종속성은 무엇입니까?

module1을 필요로하는 module2와 module2를 필요로하는 module1을 가지고 있다면 어떻게됩니까? 오류?

// 모듈 1
require ( './ module2');
// 모듈 2
require ( './ module1');

오류가 발생하지 않습니다. 노드는 그것을 허용합니다.

따라서 module1에는 module2가 필요하지만 module2에는 module1이 필요하고 module1은 아직 완료되지 않았으므로 module1은 부분 버전의 module2 만 가져옵니다.

경고를 받았습니다.

질문 # 10 : 파일 시스템 * Sync 메소드 (readFileSync와 같은)를 사용할 수있는시기

Node의 모든 fs 메소드에는 동기 버전이 있습니다. 비동기 방식 대신 동기화 방식을 사용하는 이유는 무엇입니까?

때때로 동기화 방법을 사용하는 것이 좋습니다. 예를 들어 서버가 계속로드되는 동안 초기화 단계에서 사용할 수 있습니다. 초기화 단계 후에 수행하는 모든 작업은 사용자가 얻은 데이터에 따라 달라집니다. 동기식 메소드를 사용하는 것이 일회성 인 한 콜백 레벨을 도입하는 대신 동기식 메소드를 사용할 수 있습니다.

그러나 HTTP 서버 요청시 콜백과 같은 핸들러 내에서 동기 메소드를 사용하는 경우 이는 단순히 100 % 잘못된 것입니다. 그거 하지마.

이 질문들 중 일부 또는 전부에 답할 수 있기를 바랍니다.

읽어 주셔서 감사합니다.