Skip to content

Commit a1265bf

Browse files
committed
fix(react-native): dispose blob slice chunks after consume
1 parent 4540c45 commit a1265bf

File tree

5 files changed

+65
-32
lines changed

5 files changed

+65
-32
lines changed

packages/upload-client/src/uploadFile/prepareChunks.browser.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ export const prepareChunks: PrepareChunks = async (
77
fileSize: number,
88
chunkSize: number
99
) => {
10-
return (index: number): BrowserFile =>
11-
sliceChunk(file as BrowserFile, index, fileSize, chunkSize)
10+
return {
11+
disposeChunk: () => {},
12+
disposeChunks: () => {},
13+
getChunk: (index: number): BrowserFile =>
14+
sliceChunk(file as BrowserFile, index, fileSize, chunkSize)
15+
}
1216
}

packages/upload-client/src/uploadFile/prepareChunks.node.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ export const prepareChunks: PrepareChunks = async (
77
fileSize: number,
88
chunkSize: number
99
) => {
10-
return (index: number): NodeFile =>
11-
sliceChunk(file as NodeFile, index, fileSize, chunkSize)
10+
return {
11+
disposeChunk: () => {},
12+
disposeChunks: () => {},
13+
getChunk: (index: number): NodeFile =>
14+
sliceChunk(file as NodeFile, index, fileSize, chunkSize)
15+
}
1216
}

packages/upload-client/src/uploadFile/prepareChunks.react-native.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { isReactNativeAsset } from '../tools/isFileData'
2-
import { SupportedFileInput } from '../types'
2+
import { Sliceable, SupportedFileInput } from '../types'
33
import { getBlobFromReactNativeAsset } from '../tools/getBlobFromReactNativeAsset'
44
import { sliceChunk } from './sliceChunk'
55
import { PrepareChunks } from './types'
@@ -19,17 +19,33 @@ export const prepareChunks: PrepareChunks = async (
1919
fileSize: number,
2020
chunkSize: number
2121
) => {
22-
let blob: Blob
22+
let blob: Sliceable
2323
if (isReactNativeAsset(file)) {
2424
blob = await getBlobFromReactNativeAsset(file)
2525
} else {
26-
blob = file as Blob
26+
blob = file as Sliceable
2727
}
2828

29-
const chunks: Blob[] = []
30-
return (index: number): Blob => {
31-
const chunk = sliceChunk(blob, index, fileSize, chunkSize)
32-
chunks.push(chunk)
33-
return chunk
29+
const chunks: Set<Sliceable> = new Set()
30+
return {
31+
getChunk: (index: number): Sliceable => {
32+
const chunk = sliceChunk(blob, index, fileSize, chunkSize)
33+
chunks.add(chunk)
34+
return chunk
35+
},
36+
/**
37+
* Remove references to all the chunks from the memory to make able
38+
* react-native to deallocate it
39+
*/
40+
disposeChunks: () => {
41+
chunks.clear()
42+
},
43+
/**
44+
* Remove specific chunk reference from the memory to make able react-native
45+
* to deallocate it
46+
*/
47+
disposeChunk: (chunk: Sliceable) => {
48+
chunks.delete(chunk)
49+
}
3450
}
3551
}

packages/upload-client/src/uploadFile/types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,8 @@ export type PrepareChunks = (
2828
file: SupportedFileInput,
2929
fileSize: number,
3030
chunkSize: number
31-
) => Promise<(index: number) => Sliceable>
31+
) => Promise<{
32+
getChunk: (index: number) => Sliceable
33+
disposeChunk: (chunk: Sliceable) => void
34+
disposeChunks: () => void
35+
}>

packages/upload-client/src/uploadFile/uploadMultipart.ts

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -146,27 +146,32 @@ export const uploadMultipart = async (
146146
metadata
147147
})
148148
.then(async ({ uuid, parts }) => {
149-
const getChunk = await prepareChunks(file, size, multipartChunkSize)
150-
return Promise.all([
151-
uuid,
152-
runWithConcurrency(
153-
maxConcurrentRequests,
154-
parts.map(
155-
(url, index) => (): Promise<MultipartUploadResponse> =>
156-
uploadPart(getChunk(index), url, {
157-
publicKey,
158-
contentType,
159-
onProgress: createProgressHandler(parts.length, index),
160-
signal,
161-
integration,
162-
retryThrottledRequestMaxTimes,
163-
retryNetworkErrorMaxTimes
164-
})
165-
)
149+
const { getChunk, disposeChunks, disposeChunk } = await prepareChunks(
150+
file,
151+
size,
152+
multipartChunkSize
153+
)
154+
await runWithConcurrency(
155+
maxConcurrentRequests,
156+
parts.map(
157+
(url, index) => async (): Promise<MultipartUploadResponse> => {
158+
const chunk = getChunk(index)
159+
return uploadPart(chunk, url, {
160+
publicKey,
161+
contentType,
162+
onProgress: createProgressHandler(parts.length, index),
163+
signal,
164+
integration,
165+
retryThrottledRequestMaxTimes,
166+
retryNetworkErrorMaxTimes
167+
}).finally(() => disposeChunk(chunk))
168+
}
166169
)
167-
])
170+
).finally(() => disposeChunks())
171+
172+
return uuid
168173
})
169-
.then(([uuid]) =>
174+
.then((uuid) =>
170175
multipartComplete(uuid, {
171176
publicKey,
172177
baseURL,

0 commit comments

Comments
 (0)