[비동기처리] fs.readFile을 이용한 callback, Promise 구현하기

🐶·2021년 6월 22일
4

미니 과제

목록 보기
6/15

브라우저 환경과는 다르게 Node.js 환경은 로컬 컴퓨터에서 직접 실행되므로, 파일을 불러오거나 저장하는 등의 액션이 가능합니다.

Node.js 내장 모듈 목록을 확인해보니 정말 많은 모듈들이 있었다.
그 중에서 파일 시스템 모듈은 파일을 읽거나 저장하는 기능을 구현할 수 있도록 돕는다.

해당 모듈안을 둘러보니 굉장히 많은 메소드가 있는데, 파일을 읽는 readFile이라는 메소드를 사용하여 callback과 Promise를 구현해보고자 한다.

1. callBack.js 파일 내 코드 내용

fs.readFile(path,[,options], callback) 용법을 지켜 아래와 같이 callBack을 구현해보았다.
구현해야 할 세부내용은 아래와 같다.

  • 파일을 읽고 나서 callback이 실행되어야 합니다
  • 에러가 발생할 경우, callback 첫번째 인자에 에러 객체가 전달되어야 합니다
  • callback 두번째 인자에 파일 내용이 전달되어야 합니다

    위 내용을 참고하였다. 비슷한 방식으로, callback err가 있는지 없는지에 따라 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
};

2. promiseConstructor.js 파일 내 코드 내용

part-2/02_promiseConstructor.js 에서는 callback 이라는 파라미터(인자) 대신(-->파라미터는 filePath뿐이다), Promise 객체의 reject, resolve 함수를 이용한다.

구현해야 할 세부내용은 아래와 같다.

  • Promise 형태로 리턴되어야 합니다
  • then 블록을 통하여 파일 내용이 전달되어야 합니다
  • 에러가 발생할 경우, catch 블록을 통하여 에러 객체가 전달되어야 합니다
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
};

3. basicChaining.js 파일 내 코드 내용

구현해야 할 세부내용은 아래와 같다.

  • 체이닝의 결과가 Promise 형태로 리턴되어야 합니다
  • user1.json의 내용과 user2.json 내용을 합쳐 두 객체가 담긴 배열로 리턴되어야 합니다
  • fs module을 직접 사용하지 말고, 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
}

4. promiseAll.js 파일 내 코드 내용

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
}

5. asyncAwait.js 파일 내 코드 내용

앞서 진행한 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를 이용하여 아래와 같이 나타낼 수 있다.

profile
우당탕탕 개발일기📝🤖

0개의 댓글