이미지 최적화( 업로드 )-1

박경찬·2022년 9월 3일
0

저번 포스팅 에선 이미지 최적화를 통해 미리보기와 업로드 까지 했다.
이번 포스팅은 이미지를 여러개 올릴 경우 어떤 방식으로 해야 최적화시킬수 있는지 알아보자!

파일 여러개를 업로드 하기위해서는 방법은 여러개가 있다.
위에서 처럼 스테이트를 여러개 만드는법, 배열 , 객체 형식으로 만들어 업로드 하는 방법들이 있다. 어쨋든 여러개의 파일을 넣을수 있는 공간이 필요하다.

일단 이해를 쉽게 하기위해 state의 갯수를 늘려보자!

  const [fileupload, setFileUpload] = useState<File>();
  const [fileupload1, setFileUpload1] = useState<File>();
  const [fileupload2, setFileUpload2] = useState<File>();
 const upload = await uploadFile({ variables: { file: fileupload } });
 const upload1 = await uploadFile({ variables: { file: fileupload1 } });
 const upload2 = await uploadFile({ variables: { file: fileupload2 } });
const url = upload.data?.uploadFile.url;
const url1 = upload1.data?.uploadFile.url;
const url2 = upload2.data?.uploadFile.url;

우엑.. 벌써부터 코드가 많아진걸 볼수가 있다.. 상황에 따라 코드는 달라지겠지만.. 굳이 이렇게 할필요는 없다 ..

만들어진 url를 이용해 백엔드로 요청한다.

const result = await createBoard({
        variables: {
          createBoardInput: {
            writer: "Chan",
            title: "image",
            contents: "이미지 업로드",
            images: [url , url2, url3],
          },
        },
      });

 for ( let i=0; i<=3; i++){
        await uploadFile({ variables: { file: fileupload[i] } });
      }

for문을 사용하게 되면 불필요한 코드를 줄일수는 있지만 성능상으로는 똑같다. 좋아지거나 달라지는건 없다.

그러면 성능까지 얻어가려면 어떻게 해야할까 ? 오늘은 그부분에서 얘기해보도록 하겠다.

일단!! 필자는 promise를 이용하기 때문에 간단하게 promise를 어떻게 사용할건지 보고 가쟈.

export default function PromiseAllPage() {
  const onClickPromise = () => {
      new Promise((resolve, reject) => {
      resolve("A");
    }).then(res => res)
  };

  };

  const onClickPromiseAll = () => {};

  return (
    <div>
      <button onClick={onClickPromise}>Promise 연습하기</button>
      <button onClick={onClickPromiseAll}>Promise.all 연습하기</button>
    </div>
  );
}

2개의 함수로 promise를 간단하게 테스트해보자.
resolve가 실행되면 결과값을 A를 받아 then 으로 넘겨준다. 즉 resA가 된다. reject가 실행되면 에러가 생겨 함수가 작동하지 않는다.

aync await 의 출현으로 이후에는 이렇게 작성해준다.

 const result = await new Promise((resolve, reject) => {
      resolve("A");
    })

이렇게 되면 Aresult 에 담기게 된다.

그리고 Promise는 시간이 걸리는 작업을 할때 주로 쓰는데
위 코드는 A가 바로 결과값으로 주어진다. 굳이 Promise를 사용하는 의미가 없다. 조금더 의미 있게 사용하려면 아래와 같이 작성해주면 된다.

 const result = await new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("A");
      }, 3000);
    });

3초를 기다렸다가 결과값을 달라는 말이지만 정확하게 말하면 resolve가 실행될때 까지 기다린다고 생각 하면된다.

다른방법은 await 말고 .then을 사용하면된다.

 new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("A");
      }, 3000);
    }).then((res) => res);

잠깐 전에 파일 업로드 했던 코드를 보자.

 const upload = await uploadFile({ variables: { file: fileupload } });

uploadFile이 프로미스면 awaituploadFile이 끝날때 까지 기다리고 있는거라고 생각하면된다. 대신 uploadFile은 3초가 걸릴지? 5초가 걸릴지 모른다.

다시 프로미스로 돌아가서

 new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("url");
      }, 3000);
    }).then((res) => res);

프로미스 부터 업로드 파일이 3초 걸린다! 그러면 resolve("A")가 아니라 resolve("url")이 들어가야 한다

그러면 파일을 3개 업로드 한다고 생각하면? 일단 promise를 3개 만들어 보자.

    const result1 = await new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("https://dog1.jpg");
      }, 3000);
    });
    const result2 = await new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("https://dog2.jpg");
      }, 2000);
    });
    const result3 = await new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("https://dog3.jpg");
      }, 1000);
    });
  };

resolve("https://dog1.jpg")을 업로드 하고 url를 받아 오는데 까지 3초가 걸린다! 그리고 result에 담긴다
이런식으로 각 업로드를 세번 하게 된다. 여기서 궁금한건 실제로 몇초가 걸리는지 궁금하기 때문에 확인해보자.

총 6초 걸렸다. 3초 2초 1초 를 더하면 6초! for문을 써도 똑같이 6초가 걸린다.

이걸 개선하기 위해서 Promise.all 을 사용한다.


  const onClickPromiseAll = () => {
    Promise.all([]);
  };

Promise.all 안에는 배열이 들어가게 되는데 Promise들의 배열!
동시에 실행시키 싶은 Promise들을 Promise.all에 배열 형태로 넣어주면된다.

  const onClickPromiseAll = async() => {
   const result = await Promise.all([
      new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve("https://dog1.jpg");
        }, 3000);
      }),
      new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve("https://dog2.jpg");
        }, 2000);
      }),
      new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve("https://dog3.jpg");
        }, 1000);
      }),
    ]);
  };

3개가 동시에 요청이 된다. 그리고 한번만 기다리면된다
3개가 모두 끝날때 까지 기다린다 받아 오는 순서는 1초 부터 해서 3초까지 순서대로 받아오고 먼저 받아온 url은 마지막 3초가 끝날때 까지 대기하고 있다.

이때까지 6초가 걸렸던 코드가 이제는 3초면 완료된다.

result에는 배열로 들어가게된다.["https://dog1.jpg,"https://dog2.jpg,"https://dog3.jpg]

여기서 만약 사진이 100장이라면? 100개를 다 써줄건가? 답은 아니다!!
코드를 줄여 보자.

const result = await Promise.all(
  ["https://dog1.jpg", "https://dog2.jpg","https://dog3.jpg"].map((el) => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(el);
      }, 3000);
    });
  })
);

실제로 몇초인지 확인해보자.

딱 3초! 오호return해줘야 하는 값이 존재하므로 map을 사용했다. 만약 엄청난 계산을 요구하는 내용이라면 map 보다는 for문이 퍼포먼스 적으로는 좋겠지만 이렇게 간단한 파일들을 업로드 할때는 map이 훨신더 효과적이다.

이번에는 프로미스 사용법을 다시 한번 살펴봤다. 이번에 공부한 내용은 이미지 뿐만 아니라 어디서든 업로드 하는 기능이 있다면 사용해볼만한 기능이다. 다음시간에는 프로미스를 사용해서 이미지업로드 최적화를 해보쟈!

0개의 댓글