Node.js에서 리팩토링시 사용하며, npm을 통해 다운로드 했던 모듈을 불러오는 require 함수는 어떻게 동작하나요? IIFE (Immediately Invoked Function Expression)와 연결지어 찾아보고 정리해보세요
Node.js에서 require 함수는 모듈을 불러오는 node.js의 내장 함수인데, require()를 호출하면, 즉시실행(Immediately Invoked)하여 모듈 파일인 JS 파일을 읽고, 실행시키고, 반환한다.
- 아래와 같은 example.js 파일이 있다
console.log("evaluating example.js");
const invisible = function () {
console.log("invisible");
}
exports.message = "hi";
exports.say = function () {
console.log(exports.message);
}
- example.js 파일이 아닌 곳에서 const example = require("./example.js")를 실행하면, example.js 파일이 읽히고, example은 아래와 같은 객체로 생성된다. (exports로 선언한 인스턴스만 불러 온다)
const example = require("./example.js")
{
message: "hi",
say: [Function]
}
위의 예제와 같이 object형태가 아닌 함수로 직접 받아오고 싶다면, module.exports를 사용하면 된다.
- 아래는 다시 example2.js 파일에서 생성한 함수를 module.export로 바로 export 해준다.
- 그리고, example2.js 파일 밖에서 이를 받아오면, 함수로 들어온다.
// example2.js
console.log("evaluating example2.js");
module.exports = function () {
console.log("this is example2.js");
}
// 외부에서 불러오면서 바로 함수 실행시키기
require("./example2.js")() // this is example2.js
// 외부에서 함수를 변수로 담아 다른 줄에서 콜하기
const example2 = require("./example2.js")
example2() // this is example2.js
모듈을 한번 import하고 나면 다시 import 할 필요가 없다. 만약, require 함수로 동일 모듈을 두번 호출하면, 두번째에는 모듈 JS 파일을 다시 읽어서 가져오는 것이 아니라, caching된 객체가 호출된다.
- load된 모듈은 require.cache라는 객체에 캐싱이 되고, 아래와 같이 해당 모듈이 위치하는 경로를 키 값으로 갖는다.
node > require('./example.js');
evaluating example.js
{ message: 'hi', say: [Function (anonymous)] }
node > console.log(require.cache);
evaluating example.js
[Object: null prototype] {
'c:\\example.js': Module {
id: 'c:\\example.js',
path: 'c:\\',
exports: { message: 'hi', say: [Function (anonymous)] },
filename: 'c:\\example.js',
loaded: true,
children: [],
paths: [
'c:\\node_modules'
]
}
}
- 만약 아래의 예제와 같이 require('./example.js').message = "hey"로 message 값을 변경해 주면, example.js 파일의 내용을 직접 수정한 것이 아니라, require.cache 객체의 속성 값을 수정하는 것이다.
- 만약, require 함수가 매번 새로 파일을 읽어서 가져온다면, message 값을 변경해 준 뒤에 다시 require 해을 때는 message에 hey가 아닌 hi가 찍혀야 한다.
node> require('./example.js')
evaluating example.js
{ message: 'hi', say: [Function] }
node> require('./example.js')
{ message: 'hi', say: [Function] }
node> require('./example.js').message = "hey" //set the message to "hey"
'hey'
node> require('./example.js') //One might think that this "reloads" the file...
{ message: 'hey', say: [Function] } //...but the message is still "hey" because of the module cache.
이런 require 함수의 캐싱 기능은 장단점이 있다.
- 장점 : 한 번 로딩 된 모듈은 캐시 객체에 저장되어 호출할 때마다 이를 재사용하기 때문에, 불필요한 메모리 사용을 피할 수 있다. (싱글톤과 비슷하게 동장한다.)
- 단점 : 두가지 단점이 존재한다. 대소문자 구분 문제와 NPM 모듈 종속성
- 대소문자 구분 : 윈도우와 맥 os에서는 대소문자 구분을 하지 않는데, node.js는 대소문자를 구분한다. 노드는 example.js와 EXAMPLE.js 파일이 같다는 것을 구분하지 못한다.
- node.js의 이런 점 때문에, 대소문자를 구분해서 require 하게 되면, 같은 파일을 두번 캐싱하게 된다.
> node require("./example.js")
{ message: 'hi', say: [Function (anonymous)] }
> node require("./EXAMPLE.js")
evaluating example.js
{ message: 'hi', say: [Function (anonymous)] }
node > console.log(require.cache);
evaluating example.js
[Object: null prototype] {
'c:\\example.js': Module {
id: 'c:\\example.js',
path: 'c:\\',
exports: { message: 'hi', say: [Function (anonymous)] },
filename: 'c:\\example.js',
loaded: true,
children: [],
paths: [
'c:\\node_modules'
]
},
'c:\\EXAMPLE.js': Module {
id: 'c:\\EXAMPLE.js',
path: 'c:\\',
exports: { message: 'hi', say: [Function (anonymous)] },
filename: 'c:\\EXAMPLE.js',
loaded: true,
children: [],
paths: [
'c:\\EXAMPLE.js'
]
}
}
- NPM 모듈 종속성
- 예를 들어서, example과 example2 모듈이 sample이라는 모듈에 종속되어 있다면, NPM version 2 이하에서는 의존하는 각 모듈에 대해 "sample"의 다른 사본을 설치한다. 하지만 이 문제는 NPM version 3 부터 수정이 되어 더이상, 동일한 모듈 두번 설치하지 않는다고 한다.
- 그렇지만, 만약, example은 sample 모듈 version 1에 종속 되어 있고, example2는 sample 모듈 version 2에 종속되어 있다면, 이때는 서로 다른 버전의 sample 모듈을 각각 설치하게 된다.
What is require? | Node.js
Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.
nodejs.org
require는 어떻게 동작할까?
Node.js를 사용하며 문득 require에 대해 궁금증이 생겼습니다. 대부분 자주 사용하는 코드를 모듈 형식으로 만들어 **module.exports**를 사용해서 객체 인스턴스를 내보내고 이를 다른 파일에서 **require
jongmin92.github.io
'항해99_10기 > 105일의 TIL & WIL' 카테고리의 다른 글
[TIL] [5주차] [20221209] object literal에서 spread operator (1) | 2022.12.09 |
---|---|
[TIL] [4주차] [20221208] 4주차 회고 - 코드리뷰와 리팩토링 / package.json, EC2 set locale, express sanitizer (1) | 2022.12.09 |
[4주차] [20221207] express에서 Router : Middleware와 Router (0) | 2022.12.07 |
[4주차] [20221206] thunder client에서 req.cookies 넘기기 (0) | 2022.12.06 |
[4주차] [20221205] Joi validation & Sequelize를 이용한 mySQL 설정 (0) | 2022.12.06 |