Skip to content

fix: revoke Blob URLs created by p5.File - #9155

Open
slash-init wants to merge 7 commits into
processing:mainfrom
slash-init:fix/file-blob-url-lifecycle
Open

slash-init wants to merge 7 commits into
processing:mainfrom
slash-init:fix/file-blob-url-lifecycle

Conversation

@slash-init

Copy link
Copy Markdown
Contributor

Resolves #9134

Changes:

  • Track Blob URLs created by p5.File._load() on the owning p5 instance.
  • Automatically revoke all tracked Blob URLs when p5.remove() is called.
  • Add p5.File.revoke() for explicitly releasing a file's Blob URL.
  • Make p5.File.revoke() idempotent and remove revoked URLs from the instance's tracking set.
  • Pass the p5 instance through both createFileInput() and Element.drop() so media files are tracked correctly.
  • Add unit tests covering Blob URL tracking, automatic cleanup, manual revocation, and both file-loading entry points.

PR Checklist

@rk-3001

rk-3001 commented Sep 9, 2026

Copy link
Copy Markdown

Hi, I'd like to take this on.
Cause: p5.File._load() creates blob URLs for audio/video files via URL.createObjectURL() but never revokes them, so they leak for the page's lifetime instead of the sketch's.
Fix: track created URLs in a _blobUrls Set on the p5 instance (passed through from createFileInput/drop), revoke + clear them in p5.remove(), and add a file.revoke() method for early manual cleanup. I'll include unit tests.
I can work on this...

@slash-init

Copy link
Copy Markdown
Contributor Author

@rk-3001 i think you should read contributor guidelines first.

@Vaivaswat2244 Vaivaswat2244 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the pr @slash-init . Matches what we discussed on the issue, left a few comments.

Comment thread src/dom/p5.File.js Outdated
Comment thread test/js/mocks.js Outdated
@slash-init
slash-init force-pushed the fix/file-blob-url-lifecycle branch from de025d3 to 6cbdcea Compare September 16, 2026 12:05
Comment thread src/core/main.js
this._userNode = node;
this._curElement = null;
this._elements = [];
this._blobUrls = new Set();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be on the p5 instance? Can it not be fully handled by p5.File itself? For cleaning up when the sketch is removed, use the remove lifecycle hook which is designed for this kind of use.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@limzykenneth Thanks for the feedback! I looked through the lifecycle code and I think I understand the direction now: move the Blob URL cleanup into p5.File and use the existing remove lifecycle hook, rather than keeping _blobUrls on the p5 instance.
The one thing I'm still unsure about is how you'd like the File to keep track of which p5 instance it belongs to. Right now _load() gets pInst explicitly for that, but from your comment on dom.js, it sounds like you'd prefer not to pass it through like this.
I could move the cleanup into a single remove hook, but I don't want to introduce another registry or ownership mechanism if there's already a pattern in p5.js that I'm missing.
Is there a particular approach you had in mind for handling the per-instance cleanup here?

Comment thread src/dom/dom.js
Comment on lines +1825 to +1828
const pInst = this;
const handleFileSelect = function (event) {
for (const file of event.target.files) {
File._load(file, callback);
File._load(file, callback, pInst);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per the above, this should not be necessary.

Comment thread src/dom/p5.File.js
Comment on lines +26 to +67
/**
* Revokes the Blob URL associated with this file, if one was created.
*
* When video or audio files are loaded via
* <a href="#/p5/createFileInput">createFileInput()</a> or
* <a href="#/p5.Element/drop">myElement.drop()</a>, p5 creates a Blob URL
* pointing to the media in browser memory. Calling `revoke()` releases that
* resource immediately instead of waiting for the sketch to be removed.
*
* @method revoke
* @for p5.File
*
* @example
* // Load a video file and release its URL when replacing it.
* let video;
* let previousFile;
*
* function setup() {
* createCanvas(100, 100);
* createFileInput(handleFile);
* }
*
* function handleFile(file) {
* if (file.type === 'video') {
* if (video) {
* video.remove();
* previousFile.revoke();
* }
*
* video = createVideo(file.data);
* previousFile = file;
* }
* }
*/
revoke() {
if (this._isBlobUrl && this.data) {
URL.revokeObjectURL(this.data);
if (this._pInst && this._pInst._blobUrls) {
this._pInst._blobUrls.delete(this.data);
}
this._isBlobUrl = false;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It needs to be clearer when and why a user might want to revoke a URL object manually like this and what the consequence of this would be.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[p5.js 2.0+ Bug Report]: Blob URLs created by p5.File._load() for video/audio files are never revoked

4 participants