-
Notifications
You must be signed in to change notification settings - Fork 24.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: fix the race condition when calling readAsDataURL after new Blob(blobs) #34096
fix: fix the race condition when calling readAsDataURL after new Blob(blobs) #34096
Conversation
@cipolleschi has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
Base commit: 4d62e0d |
Base commit: 4d62e0d |
All JS runs on a single thread in React Native. While your fix may be correct, this does not seem like the right root cause of the issue. Digging into the issue a bit more, I think I understand that on iOS there's no guarantee of ordering between On Android, all Native Modules run on a shared background thread, so I'm not sure what the issue is there. |
…er new Blob(blobs)
099c5fb
to
0e7e848
Compare
Thanks @javache Few things
Yes you are right. I know JS side is single thread. I was talking the native side.
I fixed and tested. It works
Sorry for the confusion. I have not seen Android has the race condition but I suspect I might have. For the consistent reason, I made android same as iOS |
@javache has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
This pull request was successfully merged by @wood1986 in bd12e41. When will my fix make it into a release? | Upcoming Releases |
Hey @javache is it possible to include this fix in 0.69.2? |
Please raise this in reactwg/react-native-releases#24 |
…(blobs) (#34096) Summary: ```js async () => { let blobs = []; for (let i = 0; i < 4; i++) { const res = await fetch(); blobs = [...blobs, await res.blob()] } const blob = new Blob(blobs); // <<<<<<<<<<<<<<< a return await new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.onload = async () => { await RNFS.writeFile(destPath, (fileReader.result as string).split(',')[1], 'base64'); resolve(destPath); }; fileReader.onabort = () => { reject(''); }; fileReader.onerror = (event) => { reject(''); }; fileReader.readAsDataURL(blob); // <<<<<<<<<<<<<<< b }); } ``` Sometime `fileReader.readAsDataURL` is unable to get blob from the dictionary after `new Blob(blobs)` and then reject with `Unable to resolve data for blob: blobId` in iOS or `The specified blob is invalid` in android. Because line `a` and `b` can be run in different thread. `new Blob([])` is in progress and `fileReader.readAsDataURL` accesses the blob dictionary ahead of the blob creation. The expected behaviour is it should finish new Blob([]) first and then readAsDataURL(blob) To fix that, there should be a lock inside the method `createFromParts`. For iOS, It needs to be a recursive_mutex to allow same thread to acquire lock ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> [iOS] [Fixed] - fix the race condition when calling readAsDataURL after new Blob(blobs) Pull Request resolved: #34096 Reviewed By: cipolleschi Differential Revision: D37514981 Pulled By: javache fbshipit-source-id: 4bf84ece99871276ecaa5aa1849b9145ff44dbf4
…(blobs) (facebook#34096) Summary: ```js async () => { let blobs = []; for (let i = 0; i < 4; i++) { const res = await fetch(); blobs = [...blobs, await res.blob()] } const blob = new Blob(blobs); // <<<<<<<<<<<<<<< a return await new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.onload = async () => { await RNFS.writeFile(destPath, (fileReader.result as string).split(',')[1], 'base64'); resolve(destPath); }; fileReader.onabort = () => { reject(''); }; fileReader.onerror = (event) => { reject(''); }; fileReader.readAsDataURL(blob); // <<<<<<<<<<<<<<< b }); } ``` Sometime `fileReader.readAsDataURL` is unable to get blob from the dictionary after `new Blob(blobs)` and then reject with `Unable to resolve data for blob: blobId` in iOS or `The specified blob is invalid` in android. Because line `a` and `b` can be run in different thread. `new Blob([])` is in progress and `fileReader.readAsDataURL` accesses the blob dictionary ahead of the blob creation. The expected behaviour is it should finish new Blob([]) first and then readAsDataURL(blob) To fix that, there should be a lock inside the method `createFromParts`. For iOS, It needs to be a recursive_mutex to allow same thread to acquire lock ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> [iOS] [Fixed] - fix the race condition when calling readAsDataURL after new Blob(blobs) Pull Request resolved: facebook#34096 Reviewed By: cipolleschi Differential Revision: D37514981 Pulled By: javache fbshipit-source-id: 4bf84ece99871276ecaa5aa1849b9145ff44dbf4 (cherry picked from commit 112d678)
…(blobs) (facebook#34096) Summary: ```js async () => { let blobs = []; for (let i = 0; i < 4; i++) { const res = await fetch(); blobs = [...blobs, await res.blob()] } const blob = new Blob(blobs); // <<<<<<<<<<<<<<< a return await new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.onload = async () => { await RNFS.writeFile(destPath, (fileReader.result as string).split(',')[1], 'base64'); resolve(destPath); }; fileReader.onabort = () => { reject(''); }; fileReader.onerror = (event) => { reject(''); }; fileReader.readAsDataURL(blob); // <<<<<<<<<<<<<<< b }); } ``` Sometime `fileReader.readAsDataURL` is unable to get blob from the dictionary after `new Blob(blobs)` and then reject with `Unable to resolve data for blob: blobId` in iOS or `The specified blob is invalid` in android. Because line `a` and `b` can be run in different thread. `new Blob([])` is in progress and `fileReader.readAsDataURL` accesses the blob dictionary ahead of the blob creation. The expected behaviour is it should finish new Blob([]) first and then readAsDataURL(blob) To fix that, there should be a lock inside the method `createFromParts`. For iOS, It needs to be a recursive_mutex to allow same thread to acquire lock ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> [iOS] [Fixed] - fix the race condition when calling readAsDataURL after new Blob(blobs) Pull Request resolved: facebook#34096 Reviewed By: cipolleschi Differential Revision: D37514981 Pulled By: javache fbshipit-source-id: 4bf84ece99871276ecaa5aa1849b9145ff44dbf4 (cherry picked from commit 112d678)
Summary
Sometime
fileReader.readAsDataURL
is unable to get blob from the dictionary afternew Blob(blobs)
and then reject withUnable to resolve data for blob: blobId
in iOS orThe specified blob is invalid
in android. Because linea
andb
can be run in different thread.new Blob([])
is in progress andfileReader.readAsDataURL
accesses the blob dictionary ahead of the blob creation.The expected behaviour is it should finish new Blob([]) first and then readAsDataURL(blob)
To fix that, there should be a lock inside the method
createFromParts
. For iOS, It needs to be a recursive_mutex to allow same thread to acquire lockChangelog
[iOS] [Fixed] - fix the race condition when calling readAsDataURL after new Blob(blobs)
Test Plan