Promise 를 사용해서 file 저장 동기화

STEVELOPER·2022년 9월 28일
0

Node.js

목록 보기
1/9

회사에서 웹 프로젝트 서버 개발을 담당하다보니 file 을 저장하는 API 를 구현해야하는 일이 빈번히 있었다.
node.js express 를 통해서 REST API 방식도 사용해봤고.
graphql 을 통해서 API 구현도 해보았는데 어쨋든 파일을 받아서 저장할때는 fs 모듈의 createReadStream 이나 createWriteStream 을 사용하게 되었다.
graphql 을 사용할때는 Upload scalar type 을 만들기 때문에
API 를 통해 파라미터를 받을때 파라미터에 readStream 함수가 포함된 Promise 가 넘어온다. 그래서

const {filename, readStream} = await file;

이런식으로 file 정보를 parsing 할 수 있었다.

본론

기존의 처리방식은 하기와 같았다.

import fs from "fs";
...
//API 내부 로직
const {filename, readStream} = await file;
const _readStream = readStream;
const writeStream = fs.createWriteStream(`/uploads/${filename}`);
_readStream.pipe(writeStream);

하지만 이 경우 어떻게든 저장은 되지만 대용량 파일의 경우 어느정도의 시간이 소요되는데,
이를 기다리지 못하고 응답(response)은 반환해 버리니 아직 파일이 완벽하게 저장이 되지 않았을 경우 파일이 깨지거나 클라이언트가 바로 받을 수 없는 경우가 생겼다.
그래서 Promise 를 사용하게 되었다.

import fs from "fs";
...
//API 내부 로직
const {filename, readStream} = await file;
const _readStream = readstream;
const writeStream = fs.createWriteStream("/uploads/${filename}`);
//Promise 를 반환하는 비동기 함수 정의
const promiseExecute = async () => {
	return new Promise((resolve) => {
    	_readStream.pipe(writeStream);
        writeStream.on("finish", resolve);
    });
}
await promiseExecute();

상기 코드와 같이 Promise 를 반환하는 비동기 함수 "promiseExecute" 를 만들어서 file 이 저장될 때까지 기다리도록 만드는 것이다.
fs 모듈의 createWriteStream() 은 객체를 반환하는데, 이 객체에는 "finish" 이벤트가 있어서 file 의 저장이 완료되었는지 알 수 있다.

파일 옮기기

Promise 는 대기를 필요로하는 모든 로직에 적용해 볼 수 있다.
상기와 같은 API 의 경우 말고도 파일을 옮길 경우에도 적용해 볼 수 있다.
예를 들어서,
A 폴더에 abc.zip 이라는 대용량의 파일이 있고,
이를 B 폴더에 옮기고 싶은 상황이다.
그렇다면 현재 디렉토리 구조는 이렇다.

/A/abc.zip
/B

import fs from "fs";

const fileMove = async() => {
	//읽는 파일
	const readStream = fs.createReadStream("/A/abc.zip");
    //쓰는 파일
    const writeStream = fs.createWriteStream("/B/abc.zip");
    //Promise 사용부분
    const promiseExecute = async () => {
    	return new Promise((resolve) => {
          readStream.pipe(writeStream);
          writeStream.on("finish", resolve);
		});
 	}
    await promiseExecute();
}

await promiseExecute() 실행시 "finish" 이벤트를 통해 file 이 모두 쓰여진 후 resolve 를 하기 때문에 file 저장이 완료되었다는 것을 확신할 수 있다.

하기와 같이 resolve 에 값을 넘겨서 값을 반환 받을 수도 있다.

import fs from "fs";

const fileMove = async() => {
	//읽는 파일
	const readStream = fs.createReadStream("/A/abc.zip");
    //쓰는 파일
    const writeStream = fs.createWriteStream("/B/abc.zip");
    //Promise 사용부분
    const promiseExecute = async () => {
    	return new Promise((resolve) => {
          readStream.pipe(writeStream);
          writeStream.on("finish", () => {
          	resolve("hi");
          });
		});
 	}
    const res = await promiseExecute(); //hi
}
profile
JavaScript, Node.js, Express, React, React Native, GraphQL, Apollo, Prisma, MySQL

0개의 댓글