readAsDataURL vs createObjectURL

김기영·2022년 3월 14일
2
post-thumbnail

readAsDataURL, createObjectURL 두 가지 모두 브라우저에서 로컬 파일을 읽을 때 사용하는 방법이며 특히 이미지 미리보기에서 주로 사용된다. 두 방법의 차이는 뭐고 어떤 방법이 더 효율적일까?

비교하기 전에, 파일을 읽는 방법부터 알아보자. <input type="file" /> 또는 Drag & Drop 두가지 방법이 있으며 여기선 Drag & Drop을 사용할 것이다.

Drag & Drop 으로 파일 읽기

<body>
  <div id="file-box" class="dot-box">
    이미지 파일을 선택한 후 이곳에 끌어서 놓아주세요.
    <output id="result"></output>
  </div>
</body>
const dropZone = document.getElementById("file-box");
dropZone.addEventListener("dragover", (e) => {
  e.stopPropagation();
  e.preventDefault();
});
dropZone.addEventListener("drop", (e) => {
  e.stopPropagation();
  e.preventDefault();
  const file = e.dataTransfer.files[0];
  ...
}

drop 이벤트의 기본 동작은 새 창으로 여는 것. 따라서 stopPropagation(), preventDefault() 를 사용해서 기본 동작과 상위전파를 막았다.

drop은 이해가 가는데, dragover는 왜 사용 되었을까 하고 찾아보니 dragover의 기본동작은 drop이 안되게 하는 것이라고 한다. (???? 도대체 왜...) 따라서 drag & drop을 사용하기 위해서는 dragover의 기본 동작을 막아야한다.

이렇게 하면 e.dataTransfer.files로 파일을 읽을 수 있게 된다.

readAsDataURL

dropZone.addEventListener("drop", (e) => {
  ...
  const reader = new FileReader();
  reader.onload = (e) => {
    const imgEl = document.createElement("img");
    // console.log(e.target.result);
    imgEl.src = e.target.result;
    document.getElementById("result").appendChild(imgEl);
  };
  reader.readAsDataURL(file);
});

file을 비동기로 읽기 위한 FileReader 객체를 생성하고, onload 이벤트를 달아준다. 이후 readAsDataURL(file)을 통해 onload를 트리거 시킨다. 그러면 onload의 e.target.result 에는 Base64로 인코딩된 문자열이 저장되고, 그것을 img의 src에 넣어주면 이미지 미리보기 구현 끝.

createObjectURL

dropZone.addEventListener("drop", (e) => {
  ...
  const imgEl = document.createElement("img");
  imgEl.src = URL.createObjectURL(file);
  document.getElementById("result").appendChild(imgEl);
  /* setTimeout(() => {
    URL.revokeObjectURL(imgEl.src);
  }, 10000); */
});

URL.createObjectURL() 메서드는 주어진 객체를 가리키는 URL을 DOMString으로 반환한다. 창을 닫을 때 까지 유지되며, 그 전에 해제하기 위해서는 revokeObjectURL()을 호출해야한다.

주석을 해제해서 revokeObjectURL()을 동작시키면 src를 클릭해도 볼 수 없다.

이로써 두 방법 모두 구현 끝.

readAsDataURL vs createObjectURL

1. 메모리 효율


첫 번째 사진이 readAsDataURL의 img src, 두 번째가 createObjectURL의 img src이다. 눈으로 봐도 두 번째 사진이 문자 수가 적은 것을 알 수 있고, 심지어 첫 번째 사진에는 Show more(1.2MB)라는 문구를 보아 저기서 끝이 아님을 알 수 있다.

base64로 인코딩한 문자열을 사용하는 readAsDataURL 이지만, 반면에 createObjectURL은 포인터를 사용한다. 높은 품질의 사진이나, 비디오를 다룰 때, 둘의 차이점이 극명하게 드러난다.

위 처럼 메모리 사용량은 readAsDataURL이 훨씬 많지만, 사용하지 않을 때 가비지 콜렉터에 의해 수집되어 메모리에서 제거된다. 반면에 createObjectURL은 문서를 unload 하거나 revokeObjectURL을 실행하기 전까지 계속 메모리에 존재한다.

그래도 차이가 너무 심하다. createObjectURL 1 승

2. 속도

readAsDataURL 방법은 blob을 읽고 데이터 URL로 변환하는 데 상당한 작업이 필요하며 비동기식으로 동작한다.

createObjectURL 방법은 동기식으로 동작하며 즉시 임시 URL을 생성하고 blob에 바인딩한다. blob을 읽을 필요가 없으므로 훨씬 빠르다.

createObjectURL 2 승

번외

일반적으로 createObjectURL이 빠르지만, 용량이 작은 이미지의 경우 브라우저 마다 두 방법의 속도 차이가 있다고 한다.

https://www.andygup.net/performance-comparison-between-readasdataurl-and-createobjecturl/

3. 사용 가능 최대 용량

readAsDataURL은 약 10mb, createObjectURL은 blob의 최대치인 약 800mb 까지 가능하다고한다.

createObjectURL 3승

결론


createObjectURL 쓰자.

참고

초보를 위한 JavaScript 200제
https://stackoverflow.com/questions/31742072/filereader-vs-window-url-createobjecturl
https://www.linkedin.com/pulse/using-urlcreateobjecturl-chris-ng

profile
FE Developer

1개의 댓글

comment-user-thumbnail
2022년 3월 14일

좋은 글 감사합니다!

답글 달기