From a1265bfb8cd28cda021f663ba4083590ba06de4d Mon Sep 17 00:00:00 2001 From: nd0ut Date: Tue, 27 Feb 2024 12:31:41 +0300 Subject: [PATCH] fix(react-native): dispose blob slice chunks after consume --- .../src/uploadFile/prepareChunks.browser.ts | 8 +++- .../src/uploadFile/prepareChunks.node.ts | 8 +++- .../uploadFile/prepareChunks.react-native.ts | 32 ++++++++++---- .../upload-client/src/uploadFile/types.ts | 6 ++- .../src/uploadFile/uploadMultipart.ts | 43 +++++++++++-------- 5 files changed, 65 insertions(+), 32 deletions(-) diff --git a/packages/upload-client/src/uploadFile/prepareChunks.browser.ts b/packages/upload-client/src/uploadFile/prepareChunks.browser.ts index c77e01d64..b341c15e8 100644 --- a/packages/upload-client/src/uploadFile/prepareChunks.browser.ts +++ b/packages/upload-client/src/uploadFile/prepareChunks.browser.ts @@ -7,6 +7,10 @@ export const prepareChunks: PrepareChunks = async ( fileSize: number, chunkSize: number ) => { - return (index: number): BrowserFile => - sliceChunk(file as BrowserFile, index, fileSize, chunkSize) + return { + disposeChunk: () => {}, + disposeChunks: () => {}, + getChunk: (index: number): BrowserFile => + sliceChunk(file as BrowserFile, index, fileSize, chunkSize) + } } diff --git a/packages/upload-client/src/uploadFile/prepareChunks.node.ts b/packages/upload-client/src/uploadFile/prepareChunks.node.ts index db7f0d31f..18bd56488 100644 --- a/packages/upload-client/src/uploadFile/prepareChunks.node.ts +++ b/packages/upload-client/src/uploadFile/prepareChunks.node.ts @@ -7,6 +7,10 @@ export const prepareChunks: PrepareChunks = async ( fileSize: number, chunkSize: number ) => { - return (index: number): NodeFile => - sliceChunk(file as NodeFile, index, fileSize, chunkSize) + return { + disposeChunk: () => {}, + disposeChunks: () => {}, + getChunk: (index: number): NodeFile => + sliceChunk(file as NodeFile, index, fileSize, chunkSize) + } } diff --git a/packages/upload-client/src/uploadFile/prepareChunks.react-native.ts b/packages/upload-client/src/uploadFile/prepareChunks.react-native.ts index e0b000a95..337183865 100644 --- a/packages/upload-client/src/uploadFile/prepareChunks.react-native.ts +++ b/packages/upload-client/src/uploadFile/prepareChunks.react-native.ts @@ -1,5 +1,5 @@ import { isReactNativeAsset } from '../tools/isFileData' -import { SupportedFileInput } from '../types' +import { Sliceable, SupportedFileInput } from '../types' import { getBlobFromReactNativeAsset } from '../tools/getBlobFromReactNativeAsset' import { sliceChunk } from './sliceChunk' import { PrepareChunks } from './types' @@ -19,17 +19,33 @@ export const prepareChunks: PrepareChunks = async ( fileSize: number, chunkSize: number ) => { - let blob: Blob + let blob: Sliceable if (isReactNativeAsset(file)) { blob = await getBlobFromReactNativeAsset(file) } else { - blob = file as Blob + blob = file as Sliceable } - const chunks: Blob[] = [] - return (index: number): Blob => { - const chunk = sliceChunk(blob, index, fileSize, chunkSize) - chunks.push(chunk) - return chunk + const chunks: Set = new Set() + return { + getChunk: (index: number): Sliceable => { + const chunk = sliceChunk(blob, index, fileSize, chunkSize) + chunks.add(chunk) + return chunk + }, + /** + * Remove references to all the chunks from the memory to make able + * react-native to deallocate it + */ + disposeChunks: () => { + chunks.clear() + }, + /** + * Remove specific chunk reference from the memory to make able react-native + * to deallocate it + */ + disposeChunk: (chunk: Sliceable) => { + chunks.delete(chunk) + } } } diff --git a/packages/upload-client/src/uploadFile/types.ts b/packages/upload-client/src/uploadFile/types.ts index 853375d29..fd305db3e 100644 --- a/packages/upload-client/src/uploadFile/types.ts +++ b/packages/upload-client/src/uploadFile/types.ts @@ -28,4 +28,8 @@ export type PrepareChunks = ( file: SupportedFileInput, fileSize: number, chunkSize: number -) => Promise<(index: number) => Sliceable> +) => Promise<{ + getChunk: (index: number) => Sliceable + disposeChunk: (chunk: Sliceable) => void + disposeChunks: () => void +}> diff --git a/packages/upload-client/src/uploadFile/uploadMultipart.ts b/packages/upload-client/src/uploadFile/uploadMultipart.ts index 37a11fcef..4e91ccf8b 100644 --- a/packages/upload-client/src/uploadFile/uploadMultipart.ts +++ b/packages/upload-client/src/uploadFile/uploadMultipart.ts @@ -146,27 +146,32 @@ export const uploadMultipart = async ( metadata }) .then(async ({ uuid, parts }) => { - const getChunk = await prepareChunks(file, size, multipartChunkSize) - return Promise.all([ - uuid, - runWithConcurrency( - maxConcurrentRequests, - parts.map( - (url, index) => (): Promise => - uploadPart(getChunk(index), url, { - publicKey, - contentType, - onProgress: createProgressHandler(parts.length, index), - signal, - integration, - retryThrottledRequestMaxTimes, - retryNetworkErrorMaxTimes - }) - ) + const { getChunk, disposeChunks, disposeChunk } = await prepareChunks( + file, + size, + multipartChunkSize + ) + await runWithConcurrency( + maxConcurrentRequests, + parts.map( + (url, index) => async (): Promise => { + const chunk = getChunk(index) + return uploadPart(chunk, url, { + publicKey, + contentType, + onProgress: createProgressHandler(parts.length, index), + signal, + integration, + retryThrottledRequestMaxTimes, + retryNetworkErrorMaxTimes + }).finally(() => disposeChunk(chunk)) + } ) - ]) + ).finally(() => disposeChunks()) + + return uuid }) - .then(([uuid]) => + .then((uuid) => multipartComplete(uuid, { publicKey, baseURL,