readAsDataURL
, createObjectURL
두 가지 모두 브라우저에서 로컬 파일을 읽을 때 사용하는 방법이며 특히 이미지 미리보기에서 주로 사용된다. 두 방법의 차이는 뭐고 어떤 방법이 더 효율적일까?
비교하기 전에, 파일을 읽는 방법부터 알아보자. <input type="file" />
또는 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
로 파일을 읽을 수 있게 된다.
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에 넣어주면 이미지 미리보기 구현 끝.
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
의 img src, 두 번째가 createObjectURL
의 img src이다. 눈으로 봐도 두 번째 사진이 문자 수가 적은 것을 알 수 있고, 심지어 첫 번째 사진에는 Show more(1.2MB)라는 문구를 보아 저기서 끝이 아님을 알 수 있다.
base64로 인코딩한 문자열을 사용하는 readAsDataURL
이지만, 반면에 createObjectURL
은 포인터를 사용한다. 높은 품질의 사진이나, 비디오를 다룰 때, 둘의 차이점이 극명하게 드러난다.
위 처럼 메모리 사용량은 readAsDataURL
이 훨씬 많지만, 사용하지 않을 때 가비지 콜렉터에 의해 수집되어 메모리에서 제거된다. 반면에 createObjectURL
은 문서를 unload 하거나 revokeObjectURL
을 실행하기 전까지 계속 메모리에 존재한다.
그래도 차이가 너무 심하다. createObjectURL
1 승
readAsDataURL
방법은 blob을 읽고 데이터 URL로 변환하는 데 상당한 작업이 필요하며 비동기식으로 동작한다.
createObjectURL
방법은 동기식으로 동작하며 즉시 임시 URL을 생성하고 blob에 바인딩한다. blob을 읽을 필요가 없으므로 훨씬 빠르다.
createObjectURL
2 승
일반적으로 createObjectURL
이 빠르지만, 용량이 작은 이미지의 경우 브라우저 마다 두 방법의 속도 차이가 있다고 한다.
https://www.andygup.net/performance-comparison-between-readasdataurl-and-createobjecturl/
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
좋은 글 감사합니다!