NodeJS 개발자에게 자주 나타나는 5가지 오류 이해

6095 단어 NodeJS개발
Nodejs는 2009년에 탄생했는데 자바스크립트를 사용했기 때문에 최근 몇 년 동안 매우 광범위한 유행을 얻었다.이것은 서버 사이드 응용 프로그램을 작성하는 데 사용되는 자바스크립트가 실행될 때이지만, "그것이 바로 자바스크립트"라는 말은 100% 정확하지 않다.
JavaScript는 단일 라인으로 신축성이 요구되는 서버에서 실행되도록 설계된 것이 아닙니다.Google Chrome의 고성능 V8 자바스크립트 엔진, libuv의 쿨한 비동기 I/O 실현 및 기타 자극적인 보충을 통해 Nodejs는 클라이언트 자바스크립트를 서버에 도입하여 수천 수만의 플러그인 연결을 처리할 수 있는 웹 자바스크립트 서버를 작성할 수 있습니다.
NodeJS는 많은 흥미로운 기초 모듈로 구축된 대형 플랫폼이다.그러나 NodeJS의 이러한 내부 구성 요소의 작업 방식에 대한 이해가 부족하기 때문에 많은 NodeJS 개발자들은 NodeJS의 행위에 대해 잘못된 이해를 하고 심각한 성능 문제와 추적하기 어려운 오류를 초래하는 응용 프로그램을 개발했다.본고에서, 나는 많은 NodeJS 개발자들 중에서 흔히 볼 수 있는 다섯 가지 잘못된 이해를 묘사할 것이다.
오해1 – EventEmitter와 이벤트 순환 관련
NodeJS 응용 프로그램을 작성할 때 NodeJS EventEmitter를 많이 사용하지만, 사람들은 EventEmitter가 NodeJS Event Loop과 관련이 있다고 오해하는데 이것은 정확하지 않다.
NodeJS 이벤트 순환은 NodeJS의 핵심으로 NodeJS에 비동기적이고 막히지 않는 입출력 메커니즘을 제공합니다.다른 유형의 비동기식 이벤트에서 완료된 이벤트를 특정 순서로 처리합니다.
반대로 NodeJS Event Emitter는 핵심적인 NodeJS API로 감청기 함수를 특정한 이벤트에 추가할 수 있습니다. 이 이벤트는 터치하면 호출됩니다.이런 행위는 비동기적으로 보인다. 왜냐하면 이벤트 처리 프로그램의 호출 시간이 처음에 이벤트 처리 프로그램으로 등록된 시간보다 늦기 때문이다.
EventEmitter 실례는 EventEmitter 실례 자체 내의 사건과 관련된 모든 사건과 그 실례 자체를 추적합니다.이벤트 순환 대기열에서 이벤트를 스케줄링하지 않습니다.이 정보를 저장하는 데이터 구조는 일반적인 구식 자바스크립트 대상일 뿐입니다. 그 중에서 대상 속성은 이벤트 이름이고 속성의 값은 탐지기 함수나 탐지기 함수 그룹입니다.
EventEmitter 실례에서 emit 함수를 호출할 때, emitter는 예시에 등록된 모든 리셋 함수를 순서대로 동기화합니다.
다음 코드 세션을 참조하십시오.
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
myEmitter.on('myevent', () => console.log('handler1: myevent was fired!'));
myEmitter.on('myevent', () => console.log('handler2: myevent was fired!'));
myEmitter.on('myevent', () => console.log('handler3: myevent was fired!'));
myEmitter.emit('myevent');
console.log('I am the last log line');
위 코드 세그먼트의 출력은 다음과 같습니다.
handler1: myevent was fired!
handler2: myevent was fired!
handler3: myevent was fired!
I am the last log line
이벤트emitter는 모든 이벤트 처리 함수를 동기화하기 때문에 I am the lastlogline은 모든 감청 함수를 호출한 후에 출력합니다.
오해 2 - 리셋을 받는 모든 함수는 비동기적입니다.
함수가 동기화되었는지 비동기화되었는지는 함수가 실행하는 동안 비동기화 자원을 만드는지에 달려 있다.이 정의에 따라 함수를 주면 주어진 함수가 비동기적이라는 것을 확인할 수 있다.
JavaScript
NodeJS
setTimeout,setInterval,setImmediate,process.nextTick
NodeJS API
child_process,fs,net
PromiseAPI
async-await
C++ 플러그인에서 함수를 호출합니다. 이 함수는 비동기 함수(예를 들어 bcrypt)로 작성됩니다.
리셋 함수를 매개 변수로 받아들이면 함수가 비동기화되지 않습니다.단, 통상적으로 비동기 함수는 마지막 매개 변수로 리셋을 받아들인다 (패키지가 Promise로 되돌아오지 않는 한).리셋을 받아들여 결과를 리셋에 전달하는 이런 모델을 Continuation Passing Style이라고 부른다.Continuation Passing Style을 사용하여 동기화 기능을 작성할 수 있습니다.

const sum = (a, b, callback) => {
 callback(a + b);
};

sum(1,2, (result) => {
 console.log(result);
});
동기화 함수와 비동기 함수는 실행 기간에 창고를 어떻게 사용하는지 크게 다르다.동기화 함수는 실행되는 모든 과정에서 창고를 차지합니다. 방법은 다른 누구도 Return까지 창고를 차지하지 못하게 하는 것입니다.반대로 비동기 함수는 비동기 작업을 스케줄링하고 즉시 되돌아오기 때문에 자신을 창고에서 삭제합니다.예약된 비동기 작업이 완료되면, 제공된 모든 리셋을 호출하고, 이 리셋 함수가 다시 이 창고를 차지합니다.비동기 작업을 시작하는 함수는 이미 되돌아왔기 때문에 더 이상 사용할 수 없습니다.
상기 정의를 고려하여 다음 함수가 비동기적인지 동기적인지 확인하십시오.

function writeToMyFile(data, callback) {
  if (!data) {
    callback(new Error('No data provided'));
  } else {
    fs.writeFile('myfile.txt', data, callback);
  }
}
실제로 상술한 함수는 동기화될 수도 있고 비동기화될 수도 있으며 구체적으로 전달된 값 데이터에 달려 있다.
데이터가false라면callback은 즉시 호출되고 오류가 발생합니다.이 실행 경로에서 이 기능은 비동기식 작업을 수행하지 않기 때문에 100% 동기화됩니다.
데이터가true라면, myfile에 데이터를 기록합니다.txt, 리셋된 파일 I/O 작업을 호출합니다.비동기식 파일 입출력 작업으로 인해 이 실행 경로는 100% 비동기적입니다.
응용 프로그램의 행동을 예측할 수 없기 때문에 이러한 일치하지 않는 방식으로 (이 기능은 동기화와 비동기화 작업을 동시에 수행) 함수를 작성하지 않는 것을 강력히 권장합니다.다행히도 이러한 불일치는 다음과 같이 쉽게 복구할 수 있다.

function writeToMyFile(data, callback) {
  if (!data) {
    process.nextTick(() => callback(new Error('No data provided')));
  } else {
    fs.writeFile('myfile.txt', data, callback);
  }
}
process.nextTick은 콜백 함수의 호출을 지연시켜 실행 경로를 비동기화할 수 있습니다.
또는 프로세스 대신 setImmediate를 사용할 수 있습니다.nextTick, 이것은 많든 적든 같은 결과를 낳을 수 있다.하지만 프로세스.nextTick은 상대적으로 리셋이 더 높은 우선순위를 가지고 setImmediate보다 더 빠르다.
오해3 - CPU를 많이 사용하는 모든 기능이 이벤트 순환을 막고 있습니다.
CPU 집약형 작업은 Node를 차단하는 것으로 알려져 있습니다.js 이벤트 순환.비록 이 말은 어느 정도 정확하지만, 100% 정확하지는 않다. 왜냐하면 일부 CPU 집약형 함수는 이벤트 순환을 막지 않기 때문이다.
일반적으로 암호화 작업과 압축 작업은 CPU 높이에 의해 제한됩니다.이 때문에 일부 암호화 함수와zlib 함수의 비동기 버전은libuv 스레드 탱크에서 계산을 실행하는 방식으로 작성되어 이벤트 순환을 막지 않습니다.다음 기능 중 일부는 다음과 같습니다.
  • crypto.pbkdf2()
  • crypto.randomFill()
  • crypto.randomBytes()
  • 모든 zlib 비동기식 기능
  • 그러나 본문을 작성할 때 순수한 자바스크립트를 사용하여 libuv 스레드 탱크에서 CPU 집약형 작업을 실행할 수 없습니다.그러나, libuv 스레드 탱크의 작업을 설정할 수 있도록 C++ 플러그인을 작성할 수 있습니다.CPU 집약적 작업을 수행하고 C++ 플러그인을 사용하여 CPU 바인딩 작업에 대한 비동기식 API를 구현하는 일부 타사 라이브러리(예: bcrypt)가 있습니다.
    오해 4 - 모든 비동기식 작업이 온라인 플로팅에서 실행됨
    현대 운영체제는 내장된 코어 지원을 가지고 있으며 이벤트 알림(예를 들어 Linux의 epoll, macOS의 kqueue, Windows의 IOCP 등)을 사용하여 효과적인 방식으로 네트워크 I/O 작업을 추진할 수 있는 본기의 비동기화를 사용할 수 있다.따라서 libuv 스레드 풀에서 네트워크 I/O를 실행하지 않습니다.
    그러나 파일 I/O와 관련된 경우 운영 체제와 동일한 운영 체제에서 일치하지 않는 부분이 많습니다.따라서 파일 I/O를 위한 플랫폼과 독립적인 공통 API 구현이 매우 어렵습니다.따라서 libuv 스레드 풀에서 파일 시스템 작업을 실행하여 일치하는 비동기 API를 공개합니다.
    dns.lookup () dns 모듈의 함수는 libuv 스레드 탱크를 이용한 또 다른 API입니다.왜냐하면 dns를 사용하기 때문이다.lookup() 기능은 도메인 이름을 IP 주소로 해석하는 것은 플랫폼과 관련된 작업이며, 이 작업은 100% 네트워크 I/O가 아닙니다.
    오해 5 - NodeJS를 사용하여 CPU 집약형 어플리케이션을 작성하면 안 됩니다.
    이것은 진정한 오해가 아니라 NodeJS에 대한 모두가 알고 있는 사실이다. 현재 Node v10.5.0에 Worker Threads를 도입하여 탈락되었다.비록 이것은 실험적인 기능으로 도입되었지만,worker_threads는 Node v12 LTS에서 시작하여 현재 안정되어 있기 때문에 CPU 집약적인 조작을 가진 생산 응용 프로그램에서 사용하기에 적합하다.
    노드마다.js 작업 스레드는 자신의 v8이 실행될 때의 복사본, 이벤트 순환과libuv 스레드 탱크를 가지고 있습니다.따라서 CPU 집약적 작업을 차단하는 하나의 작업 스레드는 다른 작업 스레드의 이벤트 순환에 영향을 주지 않기 때문에 모든 전송 작업에 사용할 수 있습니다.
    그러나 이 문서를 작성할 때 IDE가 Worker Threads에 대한 지원이 가장 크지 않습니다.일부 IDE는 디버거를 주 스레드 이외의 다른 스레드에서 실행되는 코드에 추가하는 것을 지원하지 않습니다.그러나 많은 개발자들이 보조 라인을 이용하여 CPU 귀속 작업(예를 들어 비디오 인코딩 등)을 하기 시작하면서 개발 지원은 시간의 추이에 따라 성숙해질 것이다.
    이상은 본문의 전체 내용입니다. 여러분의 학습에 도움이 되고 저희를 많이 응원해 주십시오.

    좋은 웹페이지 즐겨찾기