Promise all, lazyload, preload, prefetch

yeni·2022년 12월 14일
0

현재의 이미지 업로드 방식의 비효율적인 부분은
1. 이미지 찌꺼기가 남는다
2. 이미지 미리보기가 느리다.

Promise.all

const startPromise = async () => {
        console.time("=== 개별 Promise 각각 ===");
        const result1 = await new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve("성공");
          }, 2000);
        });
        const result2 = await new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve("성공");
          }, 3000);
        });
        const result3 = await new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve("성공");
          }, 1000);
        });
        console.timeEnd("=== 개별 Promise 각각 ===");
      };

그냥 Promise로 함수를 만들어서 실행하게 되면, result1 → result2 → result3이 순차적으로 실ㄹ행되게 되고, 약 6초의 시간이 소요된다.



	const startPromiseAll = async () => {
        // await Promise.all([promise, promise, promise])

        console.time("=== 한방 Promise.all ===");
        const result = await Promise.all([
          new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve("성공");
            }, 2000);
          }),
          new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve("성공");
            }, 3000);
          }),
          new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve("성공");
            }, 1000);
          }),
        ]);
        console.log(result);
        console.timeEnd("=== 한방 Promise.all ===");
      };

Promise.all()은 그 안에 포함되어 있는 함수들을 동시에 실행하게 되어서 3초의 시간이 소요된다.

Promise.all은 Promise보다 시간을 단축하지만, 결과값은 같도록 해주는 기능이다.


LazyLoad

처음부터 다운로드 받아오지 않고, 스크롤을 내릴 때 이미지를 다운로드 받아오게 하는 것
→ 데이터의 낭비를 막을 수 있다.

Preload

다른 페이지에서 받아봐야 할 사진들을 미리 preload한 후, 글로벌한 변수에 담아서 사용하는 것.

// index.tsx
import { useRouter } from "next/router";
import { useEffect } from "react";
import { preloadImage } from "../../src/commons/libraries/preloadimage";

const PRELOAD_IMAGES = [
  "https://upload.wikimedia.org/wikipedia/commons/9/96/%22Den_kjekke_gutt%22_-_6._Internasjonale_Akademiske_Vinterleker_%281939%29_%2840200856483%29.jpg",
];



export default function ImagePreloadPage() {
  const router = useRouter();

  useEffect(() => {
   preloadImage(PRELOAD_IMAGES)
  }, []);

  const onClickMove = () => {
    void router.push("/32-06-image-preload-moved");
  };
  return (
    <>
      <button onClick={onClickMove}>페이지 이동하기</button>
    </>
  );
}


// preloadimage.ts
const PRELOADED_IMAGES: HTMLImageElement[] = [];

export const preloadImage = (images: string[]) => {
  images.forEach((el) => {
    const img = new Image();
    img.src = el;
    img.onload = () => PRELOADED_IMAGES.push(img);
  });
};

프리로드 함수는 따로 공통으로 분리해서 여기저기서 사용할 수 있다.

Prefetch

마우스 오버 하면 미리 fetch를 하는것

import { useQuery, gql, useApolloClient } from "@apollo/client";
import { useRouter } from "next/router";
import { MouseEvent } from "react";
import {
  IQuery,
  IQueryFetchBoardsArgs,
} from "../../src/commons/types/generated/types";

const FETCH_BOARDS = gql`
  query fetchBoards($page: Int) {
    fetchBoards(page: $page) {
      _id
      writer
      title
      contents
    }
  }
`;

const FETCH_BOARD = gql`
  query fetchBoard($boardId: ID!) {
    fetchBoard(boardId: $boardId) {
      _id
      writer
      title
      contents
    }
  }
`;

export default function StaticRoutedPage() {
  const router = useRouter();
  const client = useApolloClient();
  const { data, refetch } = useQuery<
    Pick<IQuery, "fetchBoards">,
    IQueryFetchBoardsArgs
  >(FETCH_BOARDS);

  console.log(data?.fetchBoards);

  const prefetchBoard = (boardId: string) => async () => {
    await client.query({
      query: FETCH_BOARD,
      variables: { boardId },
    });
  };

  const onClickMove = (boardId: string) => () => {
    void router.push(`/32-08-data-prefetch-moved/${boardId}`);
  };

  return (
    <>
      {data?.fetchBoards.map((el) => (
        <div key={el._id}>
          <span style={{ margin: "10px" }}>{el.writer}</span>
				{/* 마우스를 올렸을 때 data를 받아오도록 */}
          <span
            style={{ margin: "10px" }}
            onMouseOver={prefetchBoard(el._id)}
            onClick={onClickMove(el._id)}
          >
            {el.title}
          </span>
        </div>
      ))}
    </>
  );
}

💡 이미지 Webp 확장자
구글에서 만든 이미지 포맷으로, 기존 이미지의 용량을 줄일 수 있는 장점이 있지만, 화질이 조금 떨어질 수 있는 단점이 있다.
구글에서 jpg to webp 이런식으로 검색하면 변경할 수 있다.
💡 Google PageSpeed Insights
실제 배포를 진행하고 나서, 내가 배포한 페이지의 개선할 점을 찾을 때 유용한 사이트
💡 추천 라이브러리
react-dropzone
react-avatar-editor
react-beautiful-dnd(drop and drop)

profile
차곡차곡 쌓는 몌으니 개발노트

0개의 댓글