You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
다만 부작용이 하나 있습니다. `Blob` 매핑이 존재하는 동안엔 `Blob` 자체가 메모리에 상주합니다. 브라우저가 이를 해제할 수 없습니다.
105
105
106
-
매핑은 문서가 언로드될 때자동으로 정리되고 그때 `Blob` 객체도 함께 해제됩니다. 하지만 앱이 오래 살아 있다면 해제 시점은 금방 오지 않습니다.
106
+
매핑은 문서가 언로드될 때(탭을 닫거나 다른 페이지로 이동해서 현재 문서가 사라질 때 - 옮긴이) 자동으로 정리되고 그때 `Blob` 객체도 함께 해제됩니다. 하지만 앱이 오래 살아 있다면(탭을 몇 시간, 며칠씩 열어두는 경우가 많음 - 옮긴이) `Blob`을 더 이상 쓰지 않는 경우에도 금방 객체가 해제되지 않습니다.
107
107
108
-
**따라서 URL을 만들어 두면 그 `Blob`은 더는 필요 없어져도 메모리에 남아 있게 됩니다.**
108
+
**그렇기 때문에 URL을 만들어 두면 `Blob`이 더는 필요 없어져도 메모리에 남아 있게 됩니다.**
109
109
110
110
`URL.revokeObjectURL(url)`은 내부 매핑에서 참조를 제거합니다. 그 덕분에(다른 참조가 없다면) `Blob`이 삭제될 수 있고 메모리도 해제됩니다.
111
111
112
-
마지막 예시에선 `Blob`을 즉시 다운로드에 한 번만 쓸 생각이므로 `URL.revokeObjectURL(link.href)`를 바로 호출했습니다.
112
+
바로 위 예시에선 `Blob`을 다운로드할 때 한 번만 쓸 생각이므로 `URL.revokeObjectURL(link.href)`를 바로 호출했습니다.
113
113
114
-
클릭 가능한 HTML 링크를 쓴 이전 예시에선 `URL.revokeObjectURL(link.href)`를 호출하지 않습니다. 호출하면 `Blob` URL이 무효가 되기 때문입니다. 취소 후엔 매핑이 제거되어 URL이 더는 동작하지 않습니다.
114
+
클릭 가능한 HTML 링크를 쓴 이전 예시에선 `URL.revokeObjectURL(link.href)`를 호출하지 않았습니다. 호출하면 `Blob` URL이 무효가 되기 때문입니다. 취소 후엔 매핑이 제거되어 URL이 더는 동작하지 않습니다.
115
115
116
116
## Blob을 base64로 변환하기
117
117
118
-
`URL.createObjectURL`의 대안으로 `Blob`을 base64 인코딩 문자열로 변환하는 방법이 있습니다.
118
+
`URL.createObjectURL`을 쓰는 대신 `Blob`을 base64 인코딩 문자열로 변환하는 방법도 있습니다.
119
119
120
-
base64 인코딩은 이진 데이터를 0부터 64까지의 ASCII 코드로 이루어진 아주 안전한 '읽을 수 있는' 문자열로 표현합니다. 더 중요한 점은 이 인코딩을 '데이터 URL(data url)'에 쓸 수 있다는 사실입니다.
120
+
base64 인코딩은 이진 데이터를 0부터 64까지의 ASCII 코드만으로 이루어진 '읽을 수 있는' 안전한 문자열로 표현합니다. 더 중요한 점은 base64로 인코딩한 문자열을 '데이터 URL(data url)'에 쓸 수 있다는 사실입니다.
121
121
122
-
[데이터 URL](mdn:/http/Data_URIs)은 `data:[<mediatype>][;base64],<data>` 형태입니다. 이런 URL은 '일반' URL과 동등하게 어디에서나 사용할 수 있습니다.
122
+
[Data URL](mdn:/http/Data_URIs)은 `data:[<mediatype>][;base64],<data>` 형태입니다. 이렇게 만든 URL은 '일반' URL과 동등하게 어디에서나 사용할 수 있습니다.
브라우저가 문자열을 디코딩해 이미지를 표시합니다. <imgsrc="data:image/png;base64,R0lGODlhDAAMAKIFAF5LAP/zxAAAANyuAP/gaP///wAAAAAAACH5BAEAAAUALAAAAAAMAAwAAAMlWLPcGjDKFYi9lxKBOaGcF35DhWHamZUW0K4mAbiwWtuf0uxFAgA7">
130
+
브라우저는 문자열을 알아서 디코딩해 이미지를 표시합니다. <imgsrc="data:image/png;base64,R0lGODlhDAAMAKIFAF5LAP/zxAAAANyuAP/gaP///wAAAAAAACH5BAEAAAUALAAAAAAMAAwAAAMlWLPcGjDKFYi9lxKBOaGcF35DhWHamZUW0K4mAbiwWtuf0uxFAgA7">
131
131
132
132
133
-
`Blob`을 base64로 변환할 땐 내장 객체 `FileReader`를 사용합니다. `FileReader`는 Blob의 데이터를 여러 형식으로 읽을 수 있습니다.[다음 챕터](info:file)에서 더 자세히 다루겠습니다.
133
+
`Blob`을 base64로 변환할 땐 내장 객체 `FileReader`를 사용합니다. `FileReader`는 Blob의 데이터를 원하는 형식으로 읽어내는 객체인데, base64가 그 형식 중 하나입니다. `FileReader`는[다음 챕터](info:file)에서 더 자세히 다루겠습니다.
let blob =awaitnewPromise(resolve=>canvasElem.toBlob(resolve, 'image/png'));
206
206
```
207
207
208
-
페이지 스크린샷엔 <https://github.com/niklasvh/html2canvas> 같은 라이브러리를 사용할 수 있습니다. 이 라이브러리는 페이지를 훑으며 `<canvas>`에 그대로 그려줄 뿐입니다. 그다음은 위와 같은 방법으로`Blob`을 얻으면 됩니다.
208
+
페이지 스크린샷을 찍을 땐 <https://github.com/niklasvh/html2canvas> 같은 라이브러리를 사용할 수 있습니다. 이 라이브러리가 하는 일은 페이지를 훑으며 모든 요소를 `<canvas>`에 그대로 그리는 것뿐입니다. 그다음은 위에서 한 방법 그대로`Blob`을 얻으면 됩니다.
209
209
210
210
## Blob에서 ArrayBuffer 추출하기
211
211
212
-
`Blob` 생성자를 사용하면 `BufferSource`를 포함해 거의 모든 것으로 blob을 만들 수 있습니다.
212
+
`Blob` 생성자를 사용하면 `BufferSource`(`ArrayBuffer`나 `Uint8Array` 같은 저수준 데이터의 통칭 - 옮긴이)를 포함해 거의 모든 것으로 blob을 만들 수 있습니다.
213
213
214
-
반대로 저수준 처리가 필요하다면 `FileReader`를 사용해 blob에서 가장 저수준 형태인 `ArrayBuffer`를 얻을 수 있습니다.
214
+
반대 방향의 변환도 가능합니다. 저수준 처리가 필요하다면 `blob.arrayBuffer()`로 blob에서 가장 저수준 형태인 `ArrayBuffer`를 꺼낼 수 있습니다.
2GB가 넘는 blob을 읽고 쓸 땐 `arrayBuffer`를 사용하면 메모리 사용량이 커집니다. 이럴 땐 blob을 스트림으로 바로 변환하는 편이 좋습니다.
227
+
228
+
스트림은 조각(portion) 단위로 데이터를 읽거나 쓸 수 있는 특별한 객체입니다. 스트림 자체는 이 챕터의 범위를 벗어나는 주제라 여기선 예시만 살펴봅니다. 자세한 내용은 <https://developer.mozilla.org/en-US/docs/Web/API/Streams_API>에서 읽을 수 있습니다. 스트림은 데이터를 통째로 메모리에 올리지 않고 조각 단위로 처리하고 싶을 때 편리합니다.
229
+
230
+
`Blob` 인터페이스의 `stream()` 메서드는 `ReadableStream`을 반환합니다. 이 스트림을 읽으면 `Blob` 안에 담긴 데이터를 얻을 수 있습니다.
231
+
232
+
그다음 이렇게 스트림에서 데이터를 읽으면 됩니다.
233
+
234
+
```js
235
+
// blob에서 readableStream을 얻습니다.
236
+
constreadableStream=blob.stream();
237
+
conststream=readableStream.getReader();
238
+
239
+
while (true) {
240
+
// 반복마다 value엔 다음 blob 조각이 담깁니다.
241
+
let { done, value } =awaitstream.read();
242
+
if (done) {
243
+
// 스트림에 더 이상 데이터가 없습니다.
244
+
console.log('blob을 전부 처리했습니다.');
245
+
break;
246
+
}
247
+
248
+
// blob에서 방금 읽은 데이터 조각을 처리합니다.
249
+
console.log(value);
250
+
}
251
+
```
229
252
230
253
## 요약
231
254
232
255
`ArrayBuffer`·`Uint8Array` 등의 `BufferSource`가 '이진 데이터'라면 [Blob](https://www.w3.org/TR/FileAPI/#dfn-Blob)은 '타입이 있는 이진 데이터'를 나타냅니다.
233
256
234
-
그 덕분에 Blob은 브라우저에서 아주 흔한 업로드·다운로드 작업에 편리하게 쓰입니다.
257
+
같은 이진 데이터라도 Blob은 타입을 갖고있기 때문에 Blob은 브라우저에서 아주 흔한 작업인 업로드·다운로드에 편리하게 쓰입니다.
235
258
236
259
[XMLHttpRequest](info:xmlhttprequest)·[fetch](info:fetch) 등 웹 요청을 수행하는 메서드는 다른 이진 타입과 마찬가지로 `Blob`도 기본으로 다룰 수 있습니다.
237
260
238
-
`Blob`과 저수준 이진 데이터 타입 사이의 변환도 간단합니다.
261
+
`Blob`과 저수준 이진 데이터 타입간 변환도 간단합니다.
262
+
263
+
-`new Blob(...)` 생성자를 사용하면 TypedArray로 `Blob`을 만들 수 있습니다.
264
+
-`blob.arrayBuffer()`를 사용하면 Blob에서 `ArrayBuffer`를 다시 얻을 수 있고 그 위에 뷰를 만들어 저수준 이진 처리를 할 수 있습니다.
239
265
240
-
-`new Blob(...)` 생성자를 사용하면 TypedArray로 Blob을 만들 수 있습니다.
241
-
-`FileReader`를 사용하면 Blob에서 `ArrayBuffer`를 다시 얻을 수 있고 그 위에 뷰를 만들어 저수준 이진 처리를 할 수 있습니다.
266
+
스트림은 큰 blob을 다뤄야 할 때 아주 유용합니다. blob으로는 `ReadableStream`을 쉽게 만들 수 있습니다. `Blob` 인터페이스의 `stream()` 메서드가 반환하는 `ReadableStream`을 읽으면 blob 안에 담긴 데이터를 얻을 수 있습니다.
0 commit comments