react-native-fs
react-native-fs copied to clipboard
Download block UI thread with small file
I'm using RNFS for downloading file inside an app. Sometimes I can use the app during a download but sometimes not.
I've tested with a small file (~10Mo) and the bug occurs, but with a large file (~1Go) it doesn't.
When I check the log with XCode, I can see, with the small file, that the percentage displayed within the app is not the same that it displayed within Xcode. But with the big file I don't have this problem.
I just tested on Android too, and I get the same weird behavior.
Here is the code I'm using. I tried without progressDivider but same result.
download = (idCourse) => {
begin = (res) => {
if (res.statusCode == '404') {
this.props.cancelDownload(this.props.course.id_course)
return false
} else {
this.jobId = res.jobId
this.props.setPercentage(this.props.course.id_course, 0, this.jobId)
}
}
progress = (data) => {
const percentage = ((100 * data.bytesWritten) / data.contentLength) | 0;
this.props.setPercentage(this.props.course.id_course, percentage, this.jobId)
}
const localPath = this.props.course.id_course + '.zip';
const remoteURL = getCourseZipUrl(this.props.course.id_course)
const downloadDirectory = Platform.OS === 'ios' ? RNFS.DocumentDirectoryPath + '/downloads/' : RNFS.ExternalDirectoryPath + '/downloads/';
const realLocalPath = downloadDirectory + '/' + localPath;
const progressDivider = 1;
const ret = RNFS.downloadFile({fromUrl: remoteURL, toFile: realLocalPath, begin, progress, false, progressDivider})
ret.promise.then(res => {
if (res.statusCode == '404') {
this.props.cancelDownload(this.props.course.id_course)
} else{
this.props.setFinished(this.props.course.id_course)
}
}).catch(err => {
console.log('errorDL', err)
})
}
stopDownload = (idJob) => {
if (idJob !== -1) {
RNFS.stopDownload(idJob);
this.props.cancelDownload(this.props.course.id_course)
}
}
Without the bug

With the bug

I'm seeing very similar behavior. 9 times out of 10 the UI locks until the download completes on Android and maybe 50/50 on iOS.
Also seeing something that could be this.
In fact this is something usual. As the percentage cames from the native side, it uses the RN bridge. This bridge is async. So if a lot of “operations” are passing by this bridge in a very short amount at time we get this lag.
A pretty simple workaround is to rise up progress divider if the file is small. Or getting the percentage every X secondes
This is strange. We use downloadFile with large Zip-FIles in our Zizzle-App very unblocking. Download happens in the background, a progressbar is shown at the bottom of the screen during the download and while all that the user can navigate thru the application without any implications.
Yeah with large file it’s pretty smooth. This is exactly what I tried to explain previously. Downloading large file implies that percentage goes up slowly. So you have several seconds between each increment. As you have several secondes (or dozen or even minutes) the RN bridge is not filled, not saturated because it doesn’t received 100 events in 5 secondes... this is one of the main RN issue
Is there a workaround? I have the same issue with blocked UI. In my case I'm downloading multiple files together (calling downloadFile for each file)
I'm also experiencing this issue with small files when UI refreshes progress every second. With large files or when I increase progressDivider UI is not refreshed every second and I'm able to interact with app, though it's still laggy and some small delay exist. I also noticed that when downloading small file is completed, every touch interaction during downloading is queued and executed right after downloading completes. This issue is not present when debugging with Chrome remote debugger, it might be because all tasks are performed by Chrome instead of Android/iOS.
Edit: I managed to decrease an occurrence of blocking UI by disabling re-rendering unnecessary components, so now I'm updating only Text component. But still, app is very laggy when progress event updates Text every second.
did anyone solve this?