Node.js 동작 방식
자바스크립트 엔진인 V8과 libuv의 조합으로 구성되어 있다.
Node.js API에는 FileSystem, Crypto, HTTP 등 여러 API를 가지고 있다. 이 API들은 C++이나 C언어로 작성되어 있는 것도 있어 Javascript에서 처리하기 위해서는 Node.js Binding을 통해 처리한다.
V8에서 자바스크립트 작업을 진행하고, 파일 시스템 같은 처리가 필요할 때 Node.js API를 호출한다.
Example
Node.js가 어떻게 작업을 처리하는지 다운로드를 예로 한 번 보자.
1. Javascript로 다운로드 요청을 보낸다.
2. Node.js의 http module api를 사용해야 한다.
3. Node.js Bidning을 통하여 libuv로 할 일을 건넨다.
4. libuv를 통해 파일을 다운로드한다. 이 작업은 비동기 input/output task를 처리하도록 되어 있기 때문에 Javascript도 동시에 다른 일을 할 수 있다.
- Windows, Mac, Linux 등 파일 시스템 처리 등의 방법이 모두 다 다른데, 이를 libuv에서 핸들링해준다.
다시 정리하자면, V8이 Javascript 코드를 해석하며 Node.js APIs 중 하나의 함수를 호출하고, Node.js Binding을 통해 libuv에 원하는 작업을 처리하게 한다.
V8
Javascript 엔진으로 Javascript 코드를 실행하는 소프트웨어 구성 요소
일반적으로 Javascript 엔진은 웹 브라우저 공급업체에서 개발함.
그중 V8은 Google Chrome에서 개발되어 가장 많이 사용되는 Javascript 엔진임.
libuv
이벤트 루프를 기반으로 하는 Asynchronus I/O에 대한 지원하는 다중 플랫폼 C 라이브러리.
libuv를 사용하면 여러 플랫폼(Windows, Mac, Linux .. )의 가장 빠른 비동기 IO 인터페이스로 통일된 코드를 돌릴 수 있다는 장점이 있음.
오픈 소스 코드를 통해 확인하기
Node.js Code
우선 Node.js의 오픈 소스 코드는 https://github.com/nodejs/node에서 확인할 수 있다.
위의 디렉터리들 중 lib과 src의 소스 코드를 볼 것이다.
lib 폴더의 코드들은 Node.js API의 자바스크립트 부분이고,
scr 폴더의 코드들은 Node.js Binding의 C++ 부분으로 Javascript와 C++을 연결해준다.
libuv Code
libuv 오픈소스 코드는 https://github.com/libuv/libuv에서 확인할 수 있다.
여기에서는 src 폴더를 볼 건데, 이 안에는 unix와 win 폴더가 있다.
unix 폴더에서는 Mac과 Linux에 대한 처리가, win 폴더에서는 Windows에 대한 처리가 이루어질 것이다.
Example
fs.open()으로 파일을 여는 과정을 보자.
1. /lib/fs.js의 open 함수를 보면 Node.js Binding을 사용하는 것을 확인할 수 있다.
function open(path, flags, mode, callback) {
path = getValidatedPath(path);
if (arguments.length < 3) {
callback = flags;
flags = 'r';
mode = 0o666;
} else if (typeof mode === 'function') {
callback = mode;
mode = 0o666;
} else {
mode = parseFileMode(mode, 'mode', 0o666);
}
const flagsNumber = stringToFlags(flags);
callback = makeCallback(callback);
const req = new FSReqCallback();
req.oncomplete = callback;
binding.open(pathModule.toNamespacedPath(path),
flagsNumber,
mode,
req);
}
2. /src/node_file.cc의 Open 함수를 보면은 uv_fs_open으로 libuv 함수를 호출하는 것을 확인할 수 있다.
static void Open(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
const int argc = args.Length();
CHECK_GE(argc, 3);
BufferValue path(env->isolate(), args[0]);
CHECK_NOT_NULL(*path);
CHECK(args[1]->IsInt32());
const int flags = args[1].As<Int32>()->Value();
CHECK(args[2]->IsInt32());
const int mode = args[2].As<Int32>()->Value();
if (CheckOpenPermissions(env, path, flags).IsNothing()) return;
if (argc > 3) { // open(path, flags, mode, req)
FSReqBase* req_wrap_async = GetReqWrap(args, 3);
CHECK_NOT_NULL(req_wrap_async);
req_wrap_async->set_is_plain_open(true);
FS_ASYNC_TRACE_BEGIN1(
UV_FS_OPEN, req_wrap_async, "path", TRACE_STR_COPY(*path))
AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
uv_fs_open, *path, flags, mode);
} else { // open(path, flags, mode)
FSReqWrapSync req_wrap_sync("open", *path);
FS_SYNC_TRACE_BEGIN(open);
int result = SyncCallAndThrowOnError(
env, &req_wrap_sync, uv_fs_open, *path, flags, mode);
FS_SYNC_TRACE_END(open);
if (is_uv_error(result)) return;
env->AddUnmanagedFd(result);
args.GetReturnValue().Set(result);
}
}
3. /src/unix/fs.c의 uv__fs_open 함수를 보면 파일 오픈 동작을 확인할 수 있다. (unix)
4. /src/win/fs.c의 uv_fs_open 함수를 보면 파일 오픈 동작을 확인할 수 있다. (win)
'Web' 카테고리의 다른 글
[NodeJS] Mocha, Mochawesome, Supertest 이용하여 테스트 구현하기 (0) | 2021.12.03 |
---|---|
[HTML] 마우스 올렸을 때 설명 텍스트 띄우기 (alt 말고!!) (0) | 2021.11.25 |