내 이름은 Eugene Obrezkov이고 오늘 나는 NodeJS라는 무시무시한 플랫폼에대해 이야기 해보려고 한다. "NodeJS는 어떻게 동작하는가?"라는 아주 복잡한 질문에 대한 답을 해나갈 것이다.
나는 마치 NodeJS가 존재하지 않는다고 생각하고 글을 써내려 갈 것이다. 이렇게하면 그 내부가 어떻게 동작하는지 이해하기 쉬워진다.
여기서 사용한 코드는 실제 NodeJS에서 발췌한 코드이며 이 글을 읽고나면 NodeJS에대해 더 편안합을 느낄 수 있을 것이다.
이렇게 하려면 무엇이 필요한가?
위 이야기를 보면 막상 "이렇게 하려면 무엇이 필요한가?"라는 질문이 먼저 떠오를 것이다.
Vyacheslav Egorov는 이렇게 말했다: "JS VM은 자바스크립트 소스를 0과 1로 만드는 미지의 블랙박스라 생각하고, 더 많은 사람들이 그것을 그만 들여다본다." 이 발상은 NodeJS에도 적용시켜보았다. "NodeJS는 저수준 API를 돌아가게 해주는 미지의 블랙박스라 생각하고, 더 많은 사람들이 그것을 그만 들여다본다."
그냥 해보자!
2009년으로 돌아가면 NodeJS가 만들어지기 시작하는 시점이다.
우리는 백엔드에서 자바스크립트를 실행시키고 싶었고, 자바스크립트가 저수준 API에 접근하고 싶었다. 또한 우리의 자바스크립트를 CLI와 REPL로부터 실행시키고 싶었다. 사실 자바스크립트로 뭐든 다 하고싶었던 것이다!
이게 어떻게 가능할까? 내 머릿속에 처음 드는 생각은 브라우저였다.
브라우저
브라우저는 자바스크립트를 실행시킬 수 있다. 따라서 브라우저를 우리 앱에 합쳐 자바스크립트를 동작시키게 할까?
설마! 아래에 반드시 답해야할 질문들을 보자.
브라우저가 저수준 API를 자바스크립트로 만들까? — 아니다!
다른 곳에서 자바스크립트를 돌릴 수 있을까? — 반반이다. 좀 더 복잡한 이야기이다.
브라우저가 제공하는 모든 DOM 기능이 필요할까? — 아니다!
브라우저가 조금이라도 필요할까? — 아니다!
브라우저는 필요 없다. 자바스크립트는 브라우저 없이 실행된다.
그럼 브라우저가 자바스크립트를 실행시키는게 아니라면 무엇이 자바스크립트를 실행할까?
가상머신(Virtual Machine-VM)
가상머신(VM)이 자바스크립트를 실행한다!
VM은 고수준 프로그래밍 언어라는 추상화를 제공한다.(시스템의 저수분 ISA 추상화와 비교해보아라)
VM은 추상화이고 플랫폼에 독립적인 프로그램 실행환경을 만들기 위해 단일 컴퓨터에서 동작하도록 설계되었다.
가상머신에는 Google의 V8, 마이크로소프트의 Chakra, 모질라의 SpiderMonkey, Apple의 JavaScriptCore 등 수많은 것들이 있다. 여기서 신중하게 고르지 않으면 남은 인생동안 분명 후회하며 살 것이다.
나는 V8을 선택하려 한다. 왜일까? 그 이유는 다른 VM보다 더 빠르기 때문이다. 당신도 아마 백엔드에서 실행속도는 중요하다는 것에 동의할 것이다.
이제 V8을 살펴보면서 이것이 NodeJS 구성에 어떤 도움을 줄 수 있는지 살펴보자.
V8 VM
V8은 어떤 C++ 프로젝트와도 합칠 수 있다. 단지 간단한 라이브러리처럼 V8 소스를 거기에 인클루드(include)시키면 된다. 이렇게만 하면 이제 자바스크립트 코드를 컴파일하고 실행할 수 있다.
V8은 C++을 자바스크립트에서 사용할 수 있게 해준다. 자바스크립트로 저수준 API를 사용할 수 있게 해주는 중요한 역할을 한다.
위 두가지 포인트가 "어떻게 자바스크립트로 저수준 API에 접근할 수 있는지"에대한 대략적인 구현을 생각해볼 수 있을것이다.
다음 챕터부터는 C++ 코드로 설명을 시작할 것이기 때문에 위의 것들을 한데모아 생각해보자. 가상머신을 선택하고(우리의 경우 V8을 선택했다) -> 우리 C++ 프로젝트에 그것을 통합시킨뒤 -> V8이 C++을 자바스크립트로 사용할 수 있게 한다.
그러나 어떻게 C++코드로 작성하고 그것이 자바스크립트에서 가능할까?
V8 템플릿
V8 템플릿들을 통해 가능하다!
한 템플릿은 자바스크립트에서의 함수와 객체를 위한 청사진이다. C++ 함수와 데이터 구조체를 자바스크립트로 감싸기 위해 템플릿을 사용한다.
예를 들어보자. 구글 크롬은 C++ DOM 노드를 자바스크립트 객체로 감싸고 전역에 함수를 만들어 두기 위해 템플릿을 사용한다.
여러분도 템플릿들을 만들어 그것을 사용할 수 있다. 따라서 당신이 원하는 만큼 템플릿을 만들면 된다.
그리고 V8은 두가지 타입의 템플릿을 가지고 있다: 함수 템플릿(Function Templates)과 객체 템플릿(Object Templates)이다.
함수 템플릿은 한 함수의 청사진이다. 당신이 자바스크립트 함수로 만들고 싶은 컨텍스트에서 템플릿의 GetFunction 메소드를 호출하여 자바스크립트 인스턴스의 템플릿을 만들어 낼 수 있다. 자바스크립트 함수 인스턴스가 호출될 때 함수 템플릿이 호출되는데, 이 함수 템플릿과 C++ 콜백을 연관시킬 수도 있다.
객체 템플릿은 객체 초기화에서 함수 템플릿과 함께 만들어진 객체를 구성하는데 익숙하다. 객체 템플릿은 두가지 C++콜백 타입과 연관이 가능하다: 접근자 콜백(accessor callback)과 인터셉터 콜백(intercepter callback). 접근자 콜백은 특정 객체 프로퍼티가 스크립트에의해 접근될 때 호출된다. 인터럽트 콜백은 어떤 객체 프로퍼티라도 스크립트가 접근하면 호출된다. 즉 C++ 객체/구조체를 자바스크립트 객체로 감쌀 수 있다.
간단한 예제를 살펴보자. 이것은 C++ 메소드인 LogCallback을 전역 자바스크립트 컨텍스트에서 사용하는 것이다.
두번째 라인에서 새 ObjectTemplate를 생성한다. 그리고 3번째 라인에 FunctionTemplate를 생성하고 그것을 LogCallback이라는 C++ 메소드와 연관시킨다. 그 다음 이 FunctionTemplate를 ObjectTemplate에 세팅한다. 새 컨텍스트에서 자바스크립트를 실행시킬때 전역에서 log 메소드를 사용하도록 이 새로운 컨텍스트에 ObjectTemplate 인스턴스를 보낸다. 결과적으로 FunctionTemplate 인스턴스와 연관된 LogCallback C++ 메소드가 트리거 될 것이다.(As a result, C++ method, associated with our FunctionTemplate instance, LogCallback, will be triggered.)
여러분도 보았듯 C++에서는 자바스크립트에서 객체를 정의하는 것과 비슷하다.
그러나 이제 C++ 메소드를 어떻게 자바스크립트에 드러낼 것인지 배울 것이다. 방금처럼 수정된 컨텍스트에서 어떻게 자바스크립트 코드를 실행시키는지 살펴볼 것이다. 사실 단순하다. 그냥 요소를 컴파일하고 실행시키자.
V8 컴파일 && 자바스크립트 실행
우리가 만든 컨텍스트에서 자바스크립트를 실행하려면 V8에 컴파일(compile)과 실행(run)의 간단한 API만 호출하면 된다.
새 컨텍스트를 만들면서 자바스크립트를 실행시키는 이 예제를 살펴보자.
2번째줄을 보면 새로운 자바스크립트 컨텍스트를 만들었다(위에서 설명한 템플릿들과 함께 수정할 수 있다). 5번째줄은 자바스크립트 코드를 컴파일하고 실행하기 위해 컨텍스트를 활성화 시킨다. 8번째줄은 자바스크립트 소스로부터 새 문자열을 생성한다. 위처럼 하드코딩 할 수도 있고 파일을 읽거나 다른 방법으로도 가능하다. 11번째줄은 우리의 자바스크립트 소스를 컴파일한다. 14번째줄은 실제 실행시켜보고 결과를 기다린다. 이게 다다.
마침내 위에서 말한 테크닉들을 조합하여 우리는 간단한 NodeJS를 만들 수 있다.
C++ -> V8템플릿 -> 자바스크립트를 실행 -> ?
V8 머신을 만든다 -> 원하는 만큼 C++ 콜백과 연관된 FunctionTemplate를 만든다 -> ObjectTemplate 인스턴스를 만들고 그것에 만들어놓은 FunctionTemplate 인스턴스를 할당한다 -> 우리의 ObjectTemplate 인스턴스를 전역 객체로 한 자바스크립트 컨텍스트를 만든다 -> 이 컨텍스트에서 자바스크립트를 실행한다 -> NodeJS. 여기까지이다!
그러나 챕터 타이틀에 물음표부분의 "자바스크립트를 실행" 이후에는 무엇이 올까? 위 구현에는 약간의 문제가 있다. 굉장히 중요한 점을 하나 지나쳤다.
fs, http, crypto등과 함께 동작하는 수많은 C++ 메소드(약 10K SLOC)를 작성했다고 생각해보자. 우리는 [C++ 콜백들]을 ObjectTemplate에 할당하고 [FunctionTemplate]를 ObjectTemplate에 불러온다. 이 ObjectTemplate 자바스크립트 인스턴스를 쓰면 자바스크립트 전역에서 모든 FunctionTemplate 인스턴스에 접근할 수 있게 된다. 그리고 모든 것이 잘 동작하는 것처럼 보일 것이나..
당장에 fs이 필요없다면? crypto의 모든 기능이 필요 없다면? 전역에 모듈을 죄다 불러오지 않고 그들이 요구하는 것만 불러준다면 어떨까? 모든 C++ 콜백이 한 파일에 긴 C++ 코드를 작성하지 않는 것은 어떨까? 그래서 위 타이틀에서 "?"의 의미는..
모듈화이다!
각 C++ 모듈이 각 fs, http 나 다른 기능에 일치하기 때문에 이 모든 C++ 메소드는 모듈로 쪼개지고 각 다른 파일에 위치한다.(이 점이 개발을 쉽게 만들어준다) 자바스크립트 컨텍스트도 같은 로직이다. 전역에서 반드시 모든 자바스크립트 모듈에 접근할 수 있는게 아니라 요구에 따라 접근이 가능하다.
위의 방법을 기반으로 우리만의 모듈로더(module loader)를 구현해야 한다. C++ 코드에서 요구하는 데로 모듈을 가져오고 자바스크립트 컨텍스트도 마찬가지로 그러기 위해 모듈로더는 C++ 모듈과 자바스크립트 모듈을 불러오는 역할을 한다.
먼저 C++ 모듈부터 시작해보자.
C++ 모듈로더
이제 좀 많은 C++코드가 있을텐데, 마음 단단히 먹고 시작해보자 :)
모든 모듈로더의 기초부터 이야기 해보자면, 각 모듈 로더는 모든 모듈(혹은 그것을 어떻게 얻어내는지에대한 정보)을 담고 있는 변수를 반드시 가지고 있어야한다. C++ 모듈에 대한 정보를 가지고 있는 C++ 구조체를 정의하고 이 이름을 node_module이라 하자.
우리는 이 구조체 안에 현재 존재하는 모듈에 대한 정보를 담았다. 결과적으로 사용가능한 모든 C++ 모듈의 딕셔너리를 가진다.
위 구조체의 각 필드를 다 설명하진 않겠지만, 그중 몇개만 이야기 하고 싶다. nm_file에서는 어디서부터 그 모듈을 불러오는지 파일 이름을 저장하고 있다. nm_register_func와 nm_context_register_func에는 모듈이 필요할 때 호출하는 함수들을 담고있다. 이 함수들은 Template 인스턴스로 만들어질 것이다. 그리고 nm_modulename은 모듈 이름을 저장한다 (파일 이름이 아니다) .
다음으로 이 구조체를 도와주는 helper 메소드들이 필요하다. 우리 node_module 구조체에 정보를 저장할 수 있는 간단한 메소드를 만든 뒤 우리의 모듈 정의에서 이 메소드를 사용할 수 있다. 이것을 node_module_register라 부르자.
위에서 보이듯 여기서 하는 일이라곤 모듈 정보를 node_module 구조체에 저장하는 일 뿐이다.
이제 메크로를 이용해 이 과정을 간단하게 만들 수 있다. 당신의 C++ 모듈 안에 메크로를 정의하자. 이 메크로는 단지 node_module_register 메소드를 감싸는 용도이다.
첫번째 메크로는 node_module_register 메소드를 감싸는 메크로이다. 다른 하나는 첫번째 메크로에 미리 정의된 인자를 박아둔 메크로이다. 결론적으로 modname과 regfunc라는 두 인자를 받는 메크로가 완성되었다. 이 메크로를 호출하면 새 모듈 정보를 우리의 node_module 구조체에 저장한다. 그럼 modname와 regfunc는 무엇일까? 음.. modname은 fs처럼 모듈의 이름을 뜻한다. regfunc는 이전에도 우리가 이야기한 모듈 메소드이다. 이 메소드는 V8 Template 초기화와 ObjectTemplate에 이것을 할당하는 역할을 한다.
앞에서 보았듯 각각의 C++ 모듈은 모듈 이름(modname)과 초기화 함수(regfunc)를 인자로 받는 메크로로 정의할 수 있는데, 이 메크로는 모듈이 필요할 때 호출되는 것이다. 우리에게 필요한 것은 단지 node_module 구조체로부터 정보를 읽고 regfunc 메소드를 호출할 수 있는 C++ 메소드를 만드는 것이다.
node_module 구조체에서 이름으로 모듈을 검색할 수 있는 간단한 메소드를 만들어보자. 이 메소드를 get_builtin_module이라 부를 것이다.
이 메소드는 nm_modname와 node_module 구조체의 이름이 일치하면 앞서 정의된 모듈을 반환한다.
node_module 구조체의 정보를 기반으로 C++ 모듈을 불러오고 우리의 ObjectTemplate에 V8 Template 인스턴스를 할당하는 간단한 메소드를 만들 수 있다. 그러면 이 ObjectTemplate는 자바스크립트 인스턴스에 따라 자바스크립트 컨텍스트에 보내질 것이다.
위 코드에 관해 몇가지 짚고 넘어가자면, Binding은 모듈 이름을 인자로 받는다. 이 인자는 당신이 메크로를 통해 주는 모듈 이름이다. 그리고 우리는 get_builtin_module 메소드에서 나온 이 모듈에 관한 정보를 찾아온다. 만약 찾으면 exports와 같은 유용한 인자들을 보내면서 이 모듈의 초기화 함수를 호출한다. exports는 ObjectTemplate 인스턴스이므로 exports에서 V8 Template API를 사용할 수 있다. 이 모든 동작이 끝나고 Binding ㅁ[소드의 결과물로 나온 exports 객체를 받는다. 여러분이 기억하는데로 ObjectTemplate 인스턴스는 자바스크립트 인스턴스와 Binding이 한 것을 반환할 수 있다.
마지막으로 해야할 것은 이 메소드를 자바스크립트 컨텍스트에서 사용할 수 있게 하는 것이다. 이것은 마지막 라인이 하는 일인데, FunctionTemplate에서 Binding 메소드를 감싸고 전역변수 process에 할당하는 일을 한다.
이 단계에서 process.binding('fs')를 호출하여 네이티브 바인딩을 할 수 있다.
단순함을 위해 로직을 뺀, 내장된 모듈의 예시이다.
위 코드는 process.binding('V8')를 호출하여 자바스크립트 컨텍스트로부터 이 자바스크립트 객체를 얻어내려고 자바스크립트 객체를 내보내는 "V8"이라는 바인딩을 만든다.
고맙게도 여러분들은 아직 잘 따라오고 있다.
이제 우리는 require('fs')와같이 깔끔하게 되도록 도와주는 자바스크립트 모듈 로더를 만들 것이다.
자바스크립트 모듈로더
좋다. 마지막 개선(improvements)에 감사하다. 우리는 process.binding()을 호출하고 자바스크립트 컨텍스트로부터 C++ 바인딩에 접근할 수 있게 되었다. 그러나 아직 자바스크립트 모듈에 관한 이슈는 해결된 바가 없다. 어떻게 자바스크립트 모듈을 작성하고 필요할 때 그것을 require 할 수 있을까?
먼저 모듈에는 두가지 타입이 있음을 이해해야한다. 그 중 하나는 C++ 콜백과 함께 작성된 자바스크립트 모듈이고 NodeJS에 내장된 fs, http 등과 같은 모듈들이다. 이 모듈을 NativeModule이라 부르자. 다른 모듈은 여러분이 작업하는 디렉토리 안에 있는 모듈이다. 이것을 그냥 Module이라 하자.
우리는 두가지 타입 모두 require 할 수 있어야한다. 이 말은 NodeJS로부터 NativeModule을 부르는 법과 작업 디렉토리에서 Module을 부르는 법을 알아야한다는 뜻이다.
NativeModule부터 먼저 이야기해보자.
자바스크립트에 있는 모든 NativeModule은 C++ 프로젝트로 다른 폴더에 위치한다. 이 말은 모든 자바스크립트 소스가 컴파일 시간을 가진다는 뜻이다. 이렇게하여 우리가 나중에 사용할 자바스크립트 소스를 C++ 헤더파일에 감싸 넣을 수 있게 한다.
이것을 위한 js2c.py(tools/js2c.py에 위치한)이라는 파이썬 툴이 있다. 이것은 자바스크립트 코드로 감싸진 node_natives.h 헤더파일을 생성한다. node_natives.h는 C++에서 자바스크립트 소스를 얻어내는 어떠한 C++ 코드에서도 포함될 수 있다.
이제 C++ 컨텍스트에서 자바스크립트 소스를 사용할 수 있다. — 한번 시도해보자. node_natives.h에서 자바스크립트 소스를 가져오고 그것을 ObjectTemplate 인스턴스에 할당하는 DefineJavaScript 메소드를 구현했다.
위 코드에서, 우리는 각 네이티브 자바스크립트 모듈들을 통해 돌면서 ObjectTemplate 인스턴스에 키로서 모듈이름을, 값으로서 모듈 자체를 넣었다. 마지막으로 우리가 할 일은 타겟으로 ObjectTemplate 인스턴스와 함께 DefineJavaScript를 호출하는 것이다.
이때 Binding 메소드가 유용하다. C++의 Binding 구현(C++ 모듈로더 부분)을 보면 하드코딩된 constants와 natives라는 두 바인딩이 있을 것이다. 그러므로 바인딩 이름이 natives이면 environment와 exports 객체가 DefineJavaScript 메소드와 함께 호출될 것이다. 결과적으로 자바스크립트 NativeModule은 process.binding('natives')가 호출될 때 반환될 것이다.
그래 좋다. 그러나 node.gyp 파일에서 GYP 작업을 정의하고 이것으로부터 js2c.py 툴을 호출하여 또다른 개선을 할 수 있다. 이것은 NodeJS가 컴파일 될 때 자바스크립트 소스가 node_natives.h 헤더파일로 감싸지기 때문에 이 개선을 만들 것이다.
이제부터 우리는 process.binding('natives')로 사용할 수 있는 NativeModule의 자바스크립트 소스들을 가지고 있을 수 있다. 이제 NativeModule을 위한 간단한 자바스크립트 껍데기를 만들어보자.
이제 모듈을 불러오기 위해 NativeModule.require() 안에 모듈 이름을 넣어 호출한다. 먼저 모듈이 이미 캐시에 있는지 확인한다. 있으면 캐시에서 꺼네오고 그렇지 않으면 모듈을 컴파일하고 캐시에 넣은 뒤 exports 객체로 반환한다.
이제 좀 더 아까이서 cache와 compile 메소드를 살펴보자.
cache가 하는 일은 NativeModule에 위치한 스태틱 객체 _cache에 NativeModule 인스턴스를 세팅한다.
compile 메소드가 더 흥미롭다. 먼저 (process.bind('natives')로 세팅해둔 이 스태틱 프로퍼티)_source에서 필요한 모듈의 소스를 꺼낸다. 그리고 wrap 메소드로 그 소스를 감싼다. 위 소스에서 볼 수 있듯 함수의 결과물은 exports, require, module, __filename, __dirname 인자를 받는다. 그 후 필요한 인자와 함께 이것을 호출한다. 결과적으로 NativeModule.exports를 가리키는 exports, NativeModule.require를 가리키는 require, NativeModule 그 자체를 가리키는 module, 현재 파일 이름의 문자열인 __filename을 가지는 영역에서 우리 자바스크립트 모듈이 감싸진다. 이제 여러분은 module이나 require이 자바스크립트 코드 어디에서부터 오는지 안다. 그것들은 단지 NativeModule 인스턴스를 가리키고 있다. 😃
다른 하나는 Module 로더 구현이다.
Module 로더의 구현은 기본적으로 NativeModule과 같다. 그러나 다른 점은 소스가 node_natives.h 헤더파일로부터 오는 것이 아니라 우리가 fs 네이티브 모듈이라 부르는 파일로부터 온다. 따라서 wrap, cache, compile 하는 일은 같지만 파일로부터 읽는 소스만 다르다.
좋다, 이제 우리는 어떻게 네이티브 모듈이나 여러분의 작업 디렉토리로부터 모듈을 요청하는지 안다.
마지막으로, 우리는 위의 일들을 사용하여 만든 NodeJS 환경을 실행(run)하고 준비(prepare)할 때 마다 실행되는 간단한 자바스크립트 모듈을 작성할 수 있다.
NodeJS 런타임 라이브러리?
런타임 라이브러리가 무엇일까? 이 라이브러리는 전역변수인 process, console, Buffer등을 세팅하여 코딩할 수 있는 환경을 갖추고, NodeJS CLI에 인자로 보내는 메인 스크립트를 실행한다. 이 라이브러리는 NodeJS 런타임시 모든 자바스크립트 코드가 실행되기 전에 실행되는 간단한 자바스크립트 파일로 아키브(achieve)될 수 있다.
첫번째 단계로는 전역에 모든 네이티브 모듈을 프록싱(proxying)하고 다른 전역 변수를 설정하는 것이다. 이 일은 단지 global.Buffer = NativeModule.require('buffer')나 global.process = process와 같은 일들이다.
두번째 단계는 NodeJS CLI에 인자로 보내는 메인 스크립트를 실행한다. 로직은 간단하다. process.argv[1]를 파싱하여 그 값을 객체 초기화때 값으로 Module 인스턴스를 생성한다. 따라서 Module은 파일로부터 소스를 읽을 수 있고 -> NativeModule이 했던 것처럼 미리 컴파일된 자바스크립트 소스로 캐시와 컴파일 해 둘 수 있다.
여기에 내가 더 추가할 수 있는게 없다. 굉장히 매우 간단하며, 만약 그대로 더 세부적인 것을 원한다면 노드 저장소의 src/node.js 파일을 한번 확인해보아라. 이 파일은 NodeJS 런타임시 실행되고 이 글에서 말한 모든 테크닉을 사용한다.
이것이 바로 NodeJS가 어떻게 당신의 자바스크립트 코드에서 저수분 API에 접근하며 실행하는지에관한 이야기였다. 멋지지 않는가?
하지만 아직 비동기 처리에대한 문제가 남았다. 여기서는 fs.readFile()같은 연산은 완전히 순차적으로 실행된다.
비동기 처리를 위해 어떤 것이 필요할까? 이벤트 루프이다.
이벤트 루프
이벤트 루프는 프로그램 내에서 이벤트나 메시지를 기다리고 디스패치(dispatch)하는 메시지 디스패처이다. 이것은 내부/외부 이벤트 프로바이더(보통 이벤트가 도착하기 전까지 요청을 블락시키는 것)에 요청을 만듦으로서 작업한다. 그리고 적절한 이벤트 핸들러를 호출한다(이벤트를 디스패처 한다). 선택되거나 채택될 수 있는 파일 인터페이스를 따르는 이벤트 프로바이더라면, 이벤트 루프는 리엑터(reactor)와 협력하여 사용할 수 있다. 이벤트 루프는 항상 메시지 제공자와 함께 비동기로 처리한다.
V8 환경을 생성하면 V8은 인자로 이벤트 루프를 받을 수 있다. 그러나 V8에 이벤트 루프를 세팅하기 전에 먼저 그것을 구현해놓아야한다.
이제 libuv라 불리는 그 구현을 이미 가지고 있다치자. libuv는 파일 읽기와 같은 모든 비동기 처리의 책임을 가지고 있다. libuv가 없는 NodeJS는 단지 순차적으로 자바스크립트/C++를 실행할 수 있는 도구일 뿐이다.
따라서 기본적으로 NodeJS에 libuv 소스를 인클루드 할 수 있고, 거기에 있는 libuv 기본 이벤트 루프와 함께 V8 환경을 만들 수 있다. 여기에 그 구현이 있다.
CreateEnviroment 메소드는 루프 인자로 libuv 이벤트 루프를 받는다. 우리는 V8 네임스페이스에서 Enviroment::New를 호출할 수 있고 libuv 이벤트 루프를 보낸 다음 V8 환경으로 구성할 수 있다. 여기까지가 NodeJS를 어떻게 비동기 처리 할 수 있는지에 관한 이야기였다.
libuv에대해 더 이야기하고 어떻게 동작하는지 말해주고 싶지만, 이 이야기는 다음으로 미루도록 하자. :)
Thanks!
이 글을 끝까지 읽어준 모든이에게 감사하다. 여러분이 여기까지 읽으면서 뭔가 즐겁게 배웠기를 바란다. 만약 뭔가 문제를 발견한다면 자유롭게 이 글에 커멘트해주면 된다. 그러면 가능한 빨리 내가 답변해주도록 하겠다.(옮긴이: 자유롭게 이 블로그에 댓글 달아주시면 됩니다!)
Eugene Obrezkov aka ghaiklor, Technical Leader at Onix-Systems, Kirovohrad, Ukraine.