[Node.js] Node 내장 객체
Node.js는 다양한 목적에 맞게 다양한 기능을 제공하는 여러 내장 객체를 제공합니다. 이러한 객체는 Node.js의 JavaScript 런타임의 일부이며 Node.js 애플리케이션에서 사용할 수 있습니다. Node.js에 내장된 주요 객체 중 일부는 다음과 같습니다.
이렇게 Node.js에서 내장객체가 존재함으로써 얻는 이점이 무엇일까?
- 일관성: Node.js는 개발자가 신뢰할 수 있는 표준화된 모듈 세트를 제공하여 다양한 애플리케이션에서 기능의 일관성을 보장합니다.
- 효율성: 내장된 모듈은 종종 성능에 최적화되어 파일 시스템 작업, 네트워크 통신, 암호화 작업과 같은 다양한 작업에 효율적입니다.
- 사용 편의성: Node.js 내장 객체는 파일 시스템 작업, HTTP 요청 처리, 이벤트 관리와 같은 일반적인 작업을 단순화합니다. 이를 통해 개발자는 강력하고 확장 가능한 애플리케이션을 더 쉽게 구축할 수 있습니다.
- 플랫폼 독립성: Node.js는 플랫폼별 세부 정보를 추상화하여 기본 운영 체제에 관계없이 일관된 API를 제공합니다. 이는 플랫폼 간 호환성을 촉진합니다.
- 커뮤니티 지원: Node.js와 내장 모듈이 널리 사용된다는 것은 지원을 제공하고 모범 사례를 공유하며 이러한 모듈의 개선에 기여할 수 있는 대규모 개발자 커뮤니티가 있다는 것을 의미합니다.
요약하면 Node.js 내장 객체는 파일 시스템 조작, 네트워크 통신, 암호화 등과 같은 작업에 필수적인 모듈을 제공하여 JavaScript의 기능을 향상시킵니다. 이는 Node.js의 효율성, 일관성 및 사용 편의성에 기여하여 Node.js를 서버측 개발을 위한 강력한 플랫폼으로 만듭니다.
1. 전역 개체(global):
Node.js 환경에서 global 객체는 브라우저 환경의 window 객체와 동일합니다. 여기에는 애플리케이션 전체에서 전역적으로 액세스할 수 있는 속성이 포함되어 있습니다.
// Accessing global properties
global.myVariable = 'Hello, global!';
console.log(myVariable); // Hello, global!
그러나 전역 변수를 생성하기 위해 global 개체를 사용하는 것은 권장되지 않는다는 점에 유의하는 것이 중요합니다. 일반적으로 모듈과 내보내기를 사용하여 범위를 관리하는 것이 좋습니다.
2. 프로세스 개체(process):
process 객체는 Node.js 프로세스에 대한 정보와 제어를 제공합니다. 이를 통해 환경 변수에 액세스하고, 실행 흐름을 제어하고, 운영 체제와 통신할 수 있습니다.
// Accessing process properties
console.log(process.env.NODE_ENV); // Access environment variables
console.log(process.pid); // Process ID
console.log(process.cwd()); // Current working directory
// Listening for exit event
process.on('exit', (code) => {
console.log(`Process exited with code ${code}`);
});
process 객체는 Node.js에서 현재 프로세스에 대한 정보와 제어를 제공하는 전역 객체입니다. 이 객체에는 환경과 상호 작용하고 이벤트를 처리하며 Node.js 애플리케이션의 실행을 제어하는 데 사용할 수 있는 여러 속성과 메서드가 포함되어 있습니다. 여기 process 객체의 주요 측면 몇 가지가 있습니다:
환경 변수:
process.env:
process.env 객체에는 환경 변수를 포함하여 사용자 환경이 들어 있습니다. 환경 변수는 Node.js 애플리케이션의 구성이나 동작에 영향을 미치도록 사용될 수 있는 키-값 쌍입니다.
예시:
console.log(process.env.NODE_ENV); // NODE_ENV 환경 변수에 접근
프로세스 정보:
process.pid:
process.pid 속성은 현재 Node.js 프로세스의 프로세스 ID (PID)를 반환합니다.
예시:
console.log('프로세스 ID:', process.pid);
process.title:
process.title 속성은 현재 프로세스의 제목을 가져오거나 설정합니다. 이것은 일반적으로 프로세스 관리 도구에서 표시됩니다.
예시:
console.log('프로세스 제목:', process.title);
process.arch:
process.arch 속성은 현재 Node.js 프로세스의 CPU 아키텍처를 나타내는 문자열을 반환합니다.
예시:
console.log('CPU 아키텍처:', process.arch);
process.platform:
process.platform 속성은 현재 Node.js 프로세스가 실행 중인 운영 체제 플랫폼을 나타내는 문자열을 반환합니다.
예시:
console.log('운영 체제 플랫폼:', process.platform);
실행 제어:
process.exit():
process.exit() 메서드는 지정된 종료 코드로 Node.js 프로세스를 종료합니다. 관례적으로 코드 0은 성공을 나타내고 다른 값은 오류를 나타냅니다.
예시:
process.exit(0); // 성공 상태로 종료
process.on():
process.on() 메서드는 Node.js 프로세스 라이프사이클의 다양한 이벤트에 대한 이벤트 핸들러를 등록하는 데 사용됩니다. 일반적인 이벤트로는 'exit', 'unhandledRejection', 'uncaughtException' 등이 있습니다.
예시:
process.on('exit', (code) => {
console.log(`프로세스가 코드 ${code}로 종료되었습니다`);
});
I/O 스트림:
process.stdin, process.stdout, process.stderr:
이들은 각각 Node.js 프로세스의 표준 입력, 표준 출력 및 표준 오류를 나타내는 스트림입니다. 콘솔에서 읽고 쓰기 위한 방법을 제공합니다.
예시:
process.stdout.write('안녕하세요, 표준 출력!\n');
디렉토리 및 파일 위치:
process.cwd():
process.cwd() 메서드는 Node.js 프로세스의 현재 작업 디렉터리를 반환합니다.
예시:
console.log('현재 작업 디렉터리:', process.cwd());
__dirname 및 __filename:
__dirname은 현재 모듈의 디렉터리 이름을 나타내고, __filename은 현재 모듈의 파일 이름을 나타냅니다.
예시
console.log('__dirname:', __dirname);
console.log('__filename:', __filename);
메모리 사용:
process.memoryUsage():
process.memoryUsage() 메서드는 Node.js 프로세스의 메모리 사용에 대한 정보를 설명하는 객체를 반환합니다.
예시:
const memoryUsage = process.memoryUsage();
console.log('메모리 사용:', memoryUsage);
이것은 process 객체에서 제공되는 속성 및 메서드의 몇 가지 예제일 뿐입니다. process 객체는 Node.js 런타임 환경을 관리하고 이벤트를 처리하며 실행 중인 프로세스 상태에 대한 통찰력을 얻는 강력한 도구입니다.
3. 콘솔 개체(console):
'console' 개체는 로깅 및 디버깅에 사용됩니다. 콘솔에 정보를 출력하기 위해 log(), error(), warn() 등 다양한 메소드를 제공합니다.
console.log('This is a log message.');
console.error('This is an error message.');
console.warn('This is a warning message.');
4. 버퍼 개체(Buffer):
Buffer 객체는 바이너리 데이터를 처리하는 데 사용됩니다. I/O 작업, 파일 스트림 및 네트워크 작업을 수행할 때 특히 유용합니다.
// Creating a buffer
const buffer = Buffer.from('Hello, Buffer!', 'utf-8');
console.log(buffer); // <Buffer 48 65 6c 6c 6f 2c 20 42 75 66 66 65 72 21>
버퍼를 쓰는 이유
Node.js의 버퍼는 바이너리 데이터를 효율적으로 처리하는 데 사용됩니다. 이는 원시 이진 데이터로 직접 작업하는 방법을 제공하므로 I/O 작업, 네트워크 통신, 암호화 및 데이터가 이진 형식으로 표현되는 기타 상황과 관련된 시나리오에서 특히 유용합니다. 버퍼를 사용하는 몇 가지 주요 이유는 다음과 같습니다.
- 바이너리 데이터의 효율적인 처리:
- 버퍼는 바이너리 데이터를 효율적으로 작업하기 위한 메커니즘을 제공하여 원시 바이트를 직접 조작할 수 있습니다.
- 이미지, 오디오, 비디오 파일과 같은 바이너리 데이터는 버퍼를 이용하여 효율적으로 처리하고 조작할 수 있습니다.
- 바이너리 데이터는 바이너리(base-2) 형식으로 인코딩된 정보를 의미하며, 여기서 데이터는 0과 1의 조합을 사용하여 표현됩니다. 일반적으로 ASCII 또는 유니코드와 같은 문자 집합으로 인코딩되는 사람이 읽을 수 있는 텍스트와 달리 이진 데이터는 비트와 바이트의 시퀀스로 구성됩니다.
- 이진 데이터의 예는 다음과 같습니다.
- 이미지: 이미지의 픽셀 값은 종종 이진 데이터로 표현됩니다.
- 오디오: 음파는 디지털화되어 이진 데이터로 표현될 수 있습니다.
- 실행 파일: 컴퓨터의 CPU가 실행할 수 있는 기계어 코드를 바이너리 파일로 저장합니다.
- 네트워크 패킷: 네트워크를 통해 전송되는 데이터는 종종 바이너리 형식입니다.
- 왜 바이너리 데이터를 사용하면 효율적일까?
- 이진 데이터 표현은 낮은 수준에서 정보를 인코딩하고 조작하는 데 적합하기 때문에 이미지, 오디오, 실행 파일 및 이진 콘텐츠가 포함된 기타 유형의 데이터를 효율적으로 처리할 수 있습니다. 바이너리 데이터는 비트를 나타내는 0과 1의 시퀀스로 구성되며, 이는 바이트로 그룹화되고 컴퓨터 하드웨어 수준에서 처리될 수 있습니다. 다양한 유형의 파일을 처리하는 데 바이너리 데이터가 효율적인 이유는 다음과 같습니다.
- 하위 수준 표현:
- 이진 표현: 이진 데이터는 컴퓨터의 기본 하드웨어 아키텍처에 직접적으로 대응하는 정보의 낮은 수준 표현입니다. 이는 중앙 처리 장치(CPU) 및 기타 하드웨어 구성 요소를 직접 조작하는 데 효율적입니다.
- 컴팩트한 스토리지:
- 비트 효율성: 이진 인코딩은 각 비트가 이진 선택(0 또는 1)을 나타낼 수 있으므로 공간 효율적입니다. 이러한 컴팩트함은 이미지 픽셀, 오디오 샘플 또는 실행 가능한 명령과 같은 대량의 데이터를 저장하는 데 중요합니다.
- 직접 하드웨어 상호 작용:
- 이진 산술: 컴퓨터는 하드웨어 수준에서 직접 이진 산술 연산을 수행하도록 제작되었습니다. 이진 데이터는 비트 연산, 시프트 및 기타 하위 수준 연산을 사용하여 쉽게 조작할 수 있어 처리 효율성이 높습니다.
- 메모리 액세스: 메모리 주소가 이진 표현과 잘 일치하므로 이진 데이터를 효율적으로 메모리에 로드하고 메모리에서 처리할 수 있습니다. 이를 통해 메모리에 저장된 데이터에 빠르고 직접적으로 액세스할 수 있습니다.
- 머신 수준 지침:
- 기계 코드: 기계 코드 명령이 포함된 실행 파일은 본질적으로 바이너리입니다. CPU는 기계 수준에서 이러한 명령을 실행하여 이진 데이터를 직접 해석하고 처리합니다. 이로 인해 프로그램이 효율적으로 실행됩니다.
- 유형에 따른 다양성:
- 일반 목적: 바이너리 데이터는 범용적이며 그것이 나타내는 정보 유형에 구애받지 않습니다. 이미지의 픽셀이든 오디오 샘플이든 기계어 코드이든 기본 바이너리 형식은 다양한 유형의 데이터를 표현하기 위한 다양한 기반을 제공합니다.
- 스트림 처리:
- 스트림 기반 처리: 바이너리 데이터는 스트리밍 방식으로 처리될 수 있으므로 대규모 데이터세트를 효율적으로 읽고 쓸 수 있습니다. 이는 오디오 및 비디오 스트림의 실시간 처리에 특히 중요합니다.
- 바이너리 데이터의 스트림 처리는 데이터를 연속적이고 순차적인 방식으로 처리하는 방법으로, 전체 데이터 세트를 한 번에 메모리에 로드하는 대신 데이터를 하나씩 처리하거나 "스트리밍"합니다. 이 접근 방식은 대규모 데이터 세트로 작업할 때나 실시간 처리 및 효율성이 중요한 시나리오에서 특히 유용합니다. 스트림 처리는 이미지, 오디오 및 비디오 스트림과 같은 이진 데이터 처리를 포함하여 다양한 애플리케이션에서 일반적으로 사용됩니다. 이진 데이터에 대한 스트림 처리의 주요 개념을 살펴보겠습니다.
- 스트림의 정의:
- 데이터 세그먼트: 스트림 처리에서 데이터는 스트림이라고 알려진 더 작은 세그먼트 또는 청크로 나뉩니다. 각 스트림은 전체 데이터의 일부를 나타내므로 독립적으로 처리할 수 있습니다.
- 순차 처리: 스트림은 사용 가능해지면 순차적으로 처리됩니다. 이는 처리하기 전에 전체 데이터세트를 메모리에 로드하는 것과 대조되며 이는 대규모 데이터세트에는 실용적이지 않을 수 있습니다.
- 읽기 및 쓰기 스트림:
- 읽기 가능한 스트림: 예를 들어 Node.js에서 'stream' 모듈은 데이터를 순차적으로 읽기 위한 '읽기 가능한' 스트림 인터페이스를 제공합니다. 이를 통해 관리 가능한 청크로 소스(예: 파일, 네트워크 또는 사용자 입력)에서 이진 데이터를 읽을 수 있습니다.
- 쓰기 가능한 스트림: 마찬가지로 stream 모듈은 데이터를 순차적으로 쓰기 위한 쓰기 가능한 스트림 인터페이스를 제공합니다. 이를 통해 전체 데이터세트를 메모리에 로드하지 않고도 이진 데이터를 처리하고 대상(예: 파일, 네트워크 또는 출력 장치)에 쓸 수 있습니다.
- 스트림 처리의 이점:
- 메모리 효율성: 스트림 처리는 주어진 시간에 데이터의 작은 부분만 메모리에 로드되므로 메모리 사용 공간을 최소화합니다. 이는 메모리에 완전히 들어갈 수 없는 대규모 데이터 세트로 작업할 때 특히 중요합니다.
- 실시간 처리: 스트림 처리를 통해 실시간 또는 거의 실시간에 가까운 데이터 처리가 가능합니다. 데이터 덩어리를 사용할 수 있게 되면 즉시 처리할 수 있으므로 응답 시간이 빨라지고 대기 시간이 단축됩니다.
- 확장성: 스트림 처리는 본질적으로 확장 가능합니다. 멀티 코어 시스템과 병렬 컴퓨팅 아키텍처를 활용하여 쉽게 병렬화할 수 있고 여러 스트림을 동시에 처리할 수 있습니다.
- 이벤트 중심 자연:
- 이벤트 발생기: 많은 스트림 처리 프레임워크에서는 데이터가 사용 가능해지거나 처리 마일스톤에 도달하면 이벤트가 발생합니다. 이러한 이벤트 중심 특성은 비동기식 및 비차단 처리를 허용하므로 I/O 작업을 효율적으로 처리하는 데 적합합니다.
- 이벤트 핸들러: 개발자는 이벤트 핸들러를 연결하여 데이터 도착, 오류 조건 또는 스트림 종료와 같은 이벤트에 응답할 수 있습니다. 이를 통해 스트림 처리 중에 트리거된 이벤트를 기반으로 사용자 지정 논리를 구현할 수 있습니다.
- 사용 사례:
- 파일 I/O: 전체 파일을 메모리에 로드하는 대신 대용량 파일을 청크로 읽고 쓰는 것이 스트림 처리의 일반적인 사용 사례입니다. 이는 메모리 리소스가 제한된 시나리오에서 특히 중요합니다.
- 네트워크 통신: 스트림 처리는 소켓에서 데이터를 읽거나 HTTP 요청을 처리하는 등 네트워크 통신에 널리 사용됩니다. 네트워크 자원을 효율적으로 활용할 수 있습니다.
- 오디오 및 비디오 처리: 오디오 및 비디오 스트림을 처리할 때 스트림 처리는 멀티미디어 콘텐츠의 실시간 재생, 인코딩 또는 디코딩에 매우 중요합니다.
- Node.js의 예:
- 읽기 및 쓰기 가능한 스트림: Node.js에서 fs 모듈은 파일 I/O에 대해 읽기 및 쓰기 가능한 스트림으로 작업하는 createReadStream 및 createWriteStream 함수를 제공합니다. 마찬가지로 'http' 모듈은 HTTP 요청과 응답을 처리하기 위해 스트림을 사용합니다.
- 변환 스트림: Node.js는 또한 데이터가 스트림을 통과할 때 수정하거나 변환하는 데 사용할 수 있는 Transform 스트림을 제공합니다. 이는 압축, 암호화 또는 데이터 조작과 같은 작업에 유용합니다.
- 스트림의 정의:
- 병렬성:
- 병렬 처리: 최신 컴퓨팅 아키텍처의 병렬 처리 기능을 활용하여 바이너리 데이터를 쉽게 병렬화할 수 있습니다. 이는 특히 대규모 데이터 세트와 관련된 작업에서 성능을 최적화하는 데 중요합니다.
- 상호 운용성:
- 표준화: 이미지, 오디오 및 기타 데이터 유형에 대한 많은 파일 형식이 바이너리 형식으로 표준화됩니다. 이러한 표준화는 다양한 시스템과 플랫폼 간의 상호 운용성을 보장하여 바이너리 데이터를 일관되게 교환하고 처리할 수 있도록 해줍니다.
- 하위 수준 표현:
- I/O 작업:
- 버퍼는 I/O 작업, 특히 파일 읽기/쓰기, 네트워크 데이터 처리 또는 스트림 작업 시 광범위하게 사용됩니다.
- Node.js와 외부 시스템 또는 장치 간의 효율적인 데이터 전송을 가능하게 합니다.
- 네트워크 통신:
- 버퍼는 데이터가 바이너리 형식으로 전송되는 네트워크 통신을 처리하는 데 중요합니다.
- HTTP, TCP, UDP 등의 네트워킹 프로토콜에서 바이너리 데이터를 효율적으로 보내고 받는 데 사용됩니다.
- 암호화:
- 암호화 작업에는 암호화 및 해싱 알고리즘과 같은 이진 데이터 작업이 포함되는 경우가 많습니다.
- 버퍼는 암호화 계산에 필요한 이진 데이터를 조작하는 편리한 방법을 제공합니다.
- 이미지 및 멀티미디어 조작:
- 버퍼는 이미지, 오디오 또는 비디오 데이터를 처리하거나 조작해야 하는 시나리오에서 일반적으로 사용됩니다.
- 이미지 처리 라이브러리 및 멀티미디어 애플리케이션은 효율적인 데이터 처리를 위해 버퍼를 활용합니다.
- 효율적인 문자열 조작:
- 버퍼는 개별 바이트에 직접 액세스해야 하는 시나리오에서 문자열을 효율적으로 조작하는 데 사용할 수 있습니다.
- 'utf-8', 'base64', 'hex' 등 다양한 인코딩을 사용하여 문자열로 변환할 수 있습니다.
- 바이너리 프로토콜:
- 많은 통신 프로토콜에는 특정 바이트 수준 레이아웃이 있는 이진 데이터 구조가 포함됩니다.
- 버퍼를 사용하면 개발자가 이러한 바이너리 구조를 직접 사용하여 프로토콜 구현을 용이하게 할 수 있습니다.
- 메모리 효율성:
- 버퍼는 고정된 크기의 원시 메모리 할당을 제공하므로 이진 데이터를 처리할 때 메모리 사용을 더욱 효율적으로 할 수 있습니다.
- JavaScript 문자열과 관련된 메모리 오버헤드 없이 대량의 데이터를 처리하도록 설계되었습니다.
- 스트림 처리:
- 버퍼는 데이터가 청크 또는 스트림 단위로 처리되는 스트림 처리에 필수적입니다.
- 데이터를 더 작은 부분으로 수신하거나 전송할 때 데이터를 효율적으로 처리할 수 있습니다.
- 성능:
- 버퍼는 바이너리 데이터를 직접 조작해야 하는 성능이 중요한 시나리오를 위해 설계되었습니다.
- 특정 작업에 대해 JavaScript 문자열을 사용하는 것보다 더 나은 성능을 제공합니다.
요약하자면, 버퍼는 Node.js의 기본 구성 요소로, 바이너리 데이터를 효율적으로 처리하기 위한 저수준 인터페이스를 제공합니다. 이는 바이트를 직접 조작해야 하는 시나리오에서 중요한 역할을 하며, 다양한 유형의 이진 데이터를 처리할 때 성능, 메모리 효율성 및 다양성 측면에서 이점을 제공합니다.
5. 타이머(setTimeout, setInterval, setImmediate):
Node.js는 특정 지연(setTimeout) 후, 정기적인 간격(setInterval) 및 이벤트 루프의 다음 반복(setImmediate)에서 코드 실행을 예약하는 기능을 제공합니다.
// setTimeout example
setTimeout(() => {
console.log('Delayed execution');
}, 1000);
// setInterval example
setInterval(() => {
console.log('Interval execution');
}, 2000);
// setImmediate example
setImmediate(() => {
console.log('Immediate execution');
});
6. 이벤트(EventEmitter):
'EventEmitter' 클래스는 객체가 이벤트를 내보내고 수신할 수 있도록 하는 Node.js의 핵심 부분입니다. Node.js의 많은 내장 모듈은 이벤트 기반 패턴을 사용합니다.
const EventEmitter = require('events');
// Creating an event emitter instance
const myEmitter = new EventEmitter();
// Listening for an event
myEmitter.on('myEvent', (data) => {
console.log('Event triggered with data:', data);
});
// Emitting an event
myEmitter.emit('myEvent', { message: 'Hello, Event!' });
7. 파일 시스템(fs):
fs 모듈은 파일 시스템과 상호 작용하는 방법을 제공하여 파일을 읽고 쓰고 조작할 수 있습니다.
const fs = require('fs');
// Reading a file
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
console.log('File content:', data);
});
// Writing to a file
fs.writeFile('newFile.txt', 'Hello, File!', (err) => {
if (err) {
console.error(err);
return;
}
console.log('File written successfully.');
});
8. HTTP(http):
http 모듈은 HTTP 서버를 생성하는 기능을 제공합니다. 이를 통해 들어오는 HTTP 요청을 처리하고 응답을 보낼 수 있습니다.
const http = require('http');
// Creating an HTTP server
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, HTTP server!');
});
// Listening on a port
server.listen(3000, () => {
console.log('Server running on port 3000');
});