브라우저 환경과는 다르게 Node.js 환경은 로컬 컴퓨터에서 직접 실행되므로, 파일을 불러오거나 저장하는 등의 액션이 가능합니다.
Node.js 내장 모듈 목록을 확인해보니 정말 많은 모듈들이 있었다.
그 중에서 파일 시스템 모듈은 파일을 읽거나 저장하는 기능을 구현할 수 있도록 돕는다.
해당 모듈안을 둘러보니 굉장히 많은 메소드가 있는데, 파일을 읽는 readFile
이라는 메소드를 사용하여 callback과 Promise를 구현해보고자 한다.
fs.readFile(path,[,options], callback)
용법을 지켜 아래와 같이 callBack을 구현해보았다.
구현해야 할 세부내용은 아래와 같다.
const fs = require("fs");
//파일 시스템 모듈을 불러옴. 그래야지 fs.readFile등의 메소드를 사용할 수 있음.
const getDataFromFile = function (filePath, callback) {
// TODO: fs.readFile을 이용해 작성합니다
fs.readFile(filePath, 'utf-8', (err, data) => {
if(err){
callback(err, null)
}else{
callback(null, data);
}
})
};
getDataFromFile('README.md', (err, data) => console.log(data)); //err가 null이므로 if(err)조건문을 패스하고 call(null, data)가 실행된다.
module.exports = {
getDataFromFile //타 파일에서 함수를 사용할 수 있도록 export
};
part-2/02_promiseConstructor.js 에서는 callback 이라는 파라미터(인자) 대신(-->파라미터는 filePath뿐이다), Promise 객체의 reject, resolve 함수를 이용한다.
구현해야 할 세부내용은 아래와 같다.
const fs = require("fs");
const getDataFromFilePromise = filePath => {
// return new Promise()
// TODO: Promise 및 fs.readFile을 이용해 작성합니다.
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf-8', (err, data)=>{
if(err){
reject(err);
}
else{
resolve(data);
}
})
})
};
getDataFromFilePromise('README.md')
.then(data => console.log(data)); //README파일이 잘 읽어와지면 Promise 객체의 resolve 함수가 호출되어 README 파일 데이터가 결과값으로 넘어온다. 넘어온 데이터는 .then의 콜백함수 내 인자인(data)로 들어간다.
module.exports = {
getDataFromFilePromise
};
구현해야 할 세부내용은 아래와 같다.
위의 코드내용을 보고 따라하였다.
const path = require('path');
//이번엔 path 모듈을 불러옴으로써 아래 path.join 메소드를 사용하였다.
const { getDataFromFilePromise } = require('./02_promiseConstructor'); //2번 파일의 함수를 긁어와 재사용할 수 있게 한다.
const user1Path = path.join(__dirname, 'files/user1.json');
const user2Path = path.join(__dirname, 'files/user2.json'); //You can use __dirname to check on which directories your files live -->부가 자료에서 이 내용을 찾았다. 객체가 들어있는 각 json 파일의 파일 path를 나타내는 것이라고 이해하고 넘어갔다.
// HINT: getDataFromFilePromise(user1Path) 맟 getDataFromFilePromise(user2Path) 를 이용해 작성합니다
const readAllUsersChaining = () => {
// TODO: 여러개의 Promise를 then으로 연결하여 작성합니다
let result = [];
return getDataFromFilePromise(user1Path) //
.then((value)=>{ //value={user1정보} 가 전달인자로 들어감
let parsed1 = JSON.parse(value) //파싱시키고
result.push(parsed1) //result에다가 푸시. result = [{user1정보}]인 상태.
return getDataFromFilePromise(user2Path) //또 실행시켜서 user2 정보를 전달인자로 넘김
})
.then((value)=>{
let parsed2 = JSON.parse(value)
result.push(parsed2)//result에다가 푸시. result = [{user1정보}, {user2정보}]인 상태.
return result;
})
}
readAllUsersChaining();
module.exports = {
readAllUsersChaining
}
3번째 파일과 같은 결과를 리턴해야 하지만 Promise.all을 사용한다.
Promise.all 이란 메소드를 mdn에서 찾아보니 아래와 같이 사용법을 알 수 있었다.
Promise.all을 거치고 나서 value가 어떤 형태로 넘어오는지 궁금하여 푸는 도중에 아래와 같이 콘솔로그로 확인해보았다.
const user1 = getDataFromFilePromise(user1Path)
const user2 = getDataFromFilePromise(user2Path)
return Promise.all([user1, user2])
.then((value)=>{
console.log(value)
})
--->
console.log part-2/04_promiseAll.js:14
[
'{\n' +
' "name": "김코딩",\n' +
' "age": 26,\n' +
' "sex": "Male",\n' +
' "company": {\n' +
' "name": "코드스테이츠"\n' +
' }\n' +
'}',
'{\n' +
' "name": "박해커",\n' +
' "age": 40,\n' +
' "sex": "Female",\n' +
' "company": {\n' +
' "name": "Anomymous"\n' +
' }\n' +
'}'
]
위와 같이 나오는 것으로 보아 파싱되지 않은 형태의 객체들이 배열에 들어가 있었다.
따라서 .then(파싱되지 않은 객체들의 배열 --> 각 요소들이 파싱된 배열로 만들어주는 콜백함수)
를 생각하게 되었다. 따라서 map 함수를 이용하여 구현해보았다.
코드를 종합해보자면 아래와 같다.
const path = require('path');
const { getDataFromFilePromise } = require('./02_promiseConstructor');
const user1Path = path.join(__dirname, 'files/user1.json');
const user2Path = path.join(__dirname, 'files/user2.json');
const readAllUsers = () => {
// TODO: Promise.all을 이용해 작성합니다
const user1 = getDataFromFilePromise(user1Path)
const user2 = getDataFromFilePromise(user2Path)
return Promise.all([user1, user2])
.then((value)=>{
return value.map((el)=> JSON.parse(el))
})
}
readAllUsers()
module.exports = {
readAllUsers
}
앞서 진행한 readAllUsersChaining, readAllUsers과 같은 결과를 리턴한다. 이번에는 async 및 await 키워드를 사용해서 해결해야 한다.
사용법은 아래 내용을 참고하였다.
먼저 async를 함수표현식 초반에 명시를 해준 다음, 각각의 변수로 할당하여 그 값을 콘솔로그를 통해 확인해보았다.
const readAllUsersAsyncAwait = async() => {
// TODO: async/await 키워드를 이용해 작성합니다
const user1 = await getDataFromFilePromise(user1Path)
const user2 = await getDataFromFilePromise(user2Path)
console.log(user1)
console.log(user2)
}
또 위와 같이 나오는 것을 보니...
파싱되지 않은 상태의 객체가 user1, user2이다.
따라서 리턴할 때 배열안에 user1, user2를 감싸주되, 각각 파싱을 시켜주었다.
코드를 종합해보자면...
const { get } = require('https');
const path = require('path');
const { getDataFromFilePromise } = require('./02_promiseConstructor');
const user1Path = path.join(__dirname, 'files/user1.json');
const user2Path = path.join(__dirname, 'files/user2.json');
const readAllUsersAsyncAwait = async() => {
// TODO: async/await 키워드를 이용해 작성합니다
const user1 = await getDataFromFilePromise(user1Path)
const user2 = await getDataFromFilePromise(user2Path)
return [JSON.parse(user1), JSON.parse(user2)]
}
readAllUsersAsyncAwait();
module.exports = {
readAllUsersAsyncAwait
}
그리고 에러를 잡아주는 문법 중 try catch를 이용하여 아래와 같이 나타낼 수 있다.