What is the correct method for verifying if a URL has been generated using the createObjectURL function?

In the scenario I'm facing, users are able to set an image either by providing a URL or by using bytes that are converted into a blob object URL. To prevent resource leaks, it is important to free the blob object URLs when they are changed. However, there seems to be uncertainty about whether the type of the old URL is being checked correctly. Currently, the approach is to check if the URL starts with 'blob:'. Below is a simplified function demonstrating this behavior:

var url;

for (i = 0; i < 5; i++) {
    var oldurl = url;
    console.log('i = ' + i)
    if (i == 0 || i == 2 || i == 3) {
        console.log('Switching to Object URL')
        url = URL.createObjectURL(new Blob(new Uint8Array(0),
                                           {type: 'image/png'}));
    } else {
        console.log('Switching to URL')
        url = 'https://example.com/example-image.png';
    }

    if (oldurl && oldurl.startsWith('blob:')) {
        console.log('Freeing old object url')
        URL.revokeObjectURL(oldurl);
    }
}

Is this method correct? Are there better approaches available?

I've experimented with calling URL.revokeObjectURL on non-object URLs and found that it works fine. This raises questions about the significance of accurately identifying URLs that require freeing.

Note: While this script is written in TypeScript, the concerns raised here apply equally to JavaScript.

Answer №1

It seems you hit the nail on the head; as of now, I don't see any alternative.

Answer №2

Is this the correct method to accomplish this task?

Affirmative.


In further elaboration:

Presently, my approach involves checking if the URL commences with 'blob:'.

Is this the appropriate technique? Are there alternative methods available?

To determine conclusively, referring to the specification outlining how URL.revokeObjectURL(url) should function is recommended

(emphasis added, and relevant sub-instructions are included)

https://w3c.github.io/FileAPI/#dfn-revokeObjectURL

The revokeObjectURL(url) static method must execute these steps:

  1. Identify url record as the result of parsing url.
  2. If url record’s scheme is not "blob", stop.
  3. Determine origin as the origin of url record.
  4. Determine settings as the current settings object.
  5. If origin does not match settings’s origin, stop.
  6. Remove an entry from the Blob URL Store concerning url:
    1. Designate store as the user agent’s blob URL store;
    2. Define url string as the outcome of serializing url.
    3. Remove store url string.
      1. Eradicate all entries from the map that satisfy a specific condition (i.e. match url)
      2. ...or do nothing if none exist.

Additionally, it is worth noting that the specification mentions:

This implies that rather than causing an error, attempting to revoke an unregistered URL will fail silently. Browser software may display a message in the error console in such cases.

Therefore, the deduction can be made:

  • If the Scheme of a URI is blob:, or if a string URL begins with blob:, then it constitutes a Blob URL.
    • ...thus, it is possible for it to be revoked by a script (from the same origin) invoking URL.revokeObjectURL(url).
  • Employing URL.revokeObjectURL(url) with an invalid URL will have no adverse effects (such as triggering an Error or other runtime exception). Examples of invalid URLs include:
    • Non-blob: scheme URLs (due to step 2)
    • URLs from different origins (due to step 5)
    • Previously revoked ObjectURLs (Due to step 6.3.2)
    • Syntactically valid, same-origin blob: URLs with false UUIDs (Also due to step 6.3.2)

Addendum: Regular Expression for Matching blob: Object URLs:

The Web File API specification provides a precise format for blob: URIs, enabling them to be matched using a regular-expression RegExp (assuming no alterations to the specification):

  1. Assign the empty string to result.
  2. Append the text "blob:" to result.
  3. Specify settings as the current settings object
  4. Set origin as the origin within settings.
  5. Compute serialized as the ASCII representation of origin.
  6. If serialized equals "null", adjust it to a value decided by implementation.
  7. Add serialized to result.
  8. Append U+0024 SOLIDUS (/) to result.
  9. Create a UUID RFC4122 which is represented as a string and attach it to result.
  10. Return result
  • An illustration of a blob URL produced by this process would be
    blob:https://example.org/40a5fb5a-d56d-4a33-b4e2-0acf6a8e5f64
    .

Hence, the corresponding RegExp in JS would be as follows (derived from this RegExp used for matching HTTP Origin strings):

const blobObjectUrlRegex = /^blob:(?<origin>[\w\+]+:\/\/(?=.{1,254}(?::|$))(?:(?!\d|-)(?![a-z0-9\-]{1,62}-(?:\.|:|$))[a-z0-9\-]{1,63}\b(?!\.$)\.?)+(:\d+)?)\/(?<uuid>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/;

function isBlobOrObjectUrl( url ) {
    return ( typeof url === 'string' ) && blobObjectUrlRegex.test( url );
}

Demonstration:

const objectUrlExample = 'blob:https://example.org/40a5fb5a-d56d-4a33-b4e2-0acf6a8e5f64';

const regex = /^blob:(?<origin>[\w\+]+:\/\/(?=.{1,254}(?::|$))(?:(?!\d|-)(?![a-z0-9\-]{1,62}-(?:\.|:|$))[a-z0-9\-]{1,63}\b(?!\.$)\.?)+(:\d+)?)\/(?<uuid>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/;

console.log( "Is \"%s\" an ObjectURL (aka Blob URL)? %o", objectUrlExample, regex.test( objectUrlExample ) ? "Yes" : "No" );

const nonObjectUrlExample = 'https://stackoverflow.com/questions/45941639/proper-way-to-check-if-a-url-is-the-result-of-a-createobjecturl-call';

console.log( "Is \"%s\" an ObjectURL (aka Blob URL)? %o", nonObjectUrlExample, regex.test( nonObjectUrlExample ) ? "Yes" : "No" );

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to swap out one div for another div from an external HTML page?

How can I replace a div with the id 'mainbox' in my 'index.html' page with another div found in the 'list-div.html' page? <body> <div id="divet"> Sempre caro mi fu quest'ermo colle, e questa si ...

The JSONP request connected to the user input field and button will only trigger a single time

Hello all, I'm new to this and have been searching the internet high and low to see if anyone has encountered a similar issue before, but haven't had any luck. I've been attempting to set up a JSONP request to Wikipedia that is connected to ...

Processing AJAX request without reloading the page using PHP

I need assistance with creating an image cropping tool that allows users to upload a picture, crop it, and display it on the page as an image.jpg rather than as base 64 (data:image). I have tried using HTML and JavaScript but it seems impossible, so now I ...

Troubleshooting Issue: Vue.js and Firebase not synchronized after deleting document

I am currently developing a web application that allows users to add and remove notifications. To facilitate the deletion process in Firestore, I have included an ID field in the notification document, which is also added to the data-id attribute in the D ...

Display Image based on AngularJS value

Within my data, there exists a value {{catadata2.EndorsementList['0'].Rating}}. This value can be either 3, 4, or 5. Based on this value, I am looking to display the image <img src="/assets/img/rating.png" /> a certain number of times. For ...

php script within a literal .tpl file

Is there a way to perform a json_encode within a literal javascript block in the context of a Smarty template? {literal} <script> function openWin() { var O = {php} echo json_encode($obj);{/php}; // syntax error ...

Error Message: While attempting to use the aggregate function, I encountered a CastError where the value "totalsales" could not be cast to an ObjectId for the "_id" path in the "Order" model, as it is of type string

Encountering an error: CastError: Cast to ObjectId failed for value "totalsales" (type string) at path "_id" for model "Order". I followed the code from a tutorial but received this error. Similar error occurred when _id didn't match objectId type, bu ...

An unexpected issue occurred: AngularJS module error prevented from functioning properly

I'm attempting to set up a Modal popup when an image is clicked using Bootstrap Lightbox, but I can't seem to get it working. I've followed an example with the exact same code provided below. I have downloaded the Lightbox components (*.ligh ...

Disable the setTimeout() function in order to prevent the countdown from refreshing

I have a JavaScript countdown function that is working well, but I am unsure how to stop and refresh the timer to extend the time. When I call the function again before it times out, it behaves strangely by showing two countdown timers because the updateTi ...

Using the AJAX post method to generate a JSON object from database results and send it back to a jQuery UI Dialog

I wrote a script that loads sample images from the database based on the relevant category when the page loads. Here's a simplified version of the PHP script: <?php $category = 'granite'; $samples = 'SELECT * FROM material WHERE ma ...

Advancement of a grunt chore within a digital platform

After constructing an app with grunt, I am now in the process of developing a web interface using node and angular to interact with this app. One feature I have implemented is a button that triggers a grunt task using childProcess in NodeJS: child_process ...

Angularjs changes the "&" character to "&"

Here is the AngularJS code I am using: $scope.getEventSeconds = function(){ $http.get('myfile.php', { params: { 'action': 'get_datas' } }).success(function(data){ $scope.list = data; $scop ...

A guide to swapping text in a jQuery DOM component

In order to construct HTML from a jQuery ajax response, I prefer not to nest unsightly strings in javascript and avoid using templating scripts like mustache. Instead, I decided to utilize a template HTML with display: none as shown below: <div id="mes ...

What is the best way to link the roll button to a specific video URL?

I am currently working on a project that involves assigning specific videos to 6 roll buttons for continuous play. For instance, I want the first roll button to display a yellow dice and the second button to show a blue dice, and so on. As of now, I have ...

How to use TypeScript to filter arrays with multiple dimensions

I've been attempting to filter an array with multiple filters, but I can't seem to achieve the desired outcome so far. This is my Angular component: list = [ {type: type1, code: code1}, {type: type2, code: code2}] searchElement(code?: string, ...

Understanding the concept of Angular factories in Javascript

app.service('WeatherService', function($http) { var service = {}; service.getLocation = function() { return $http.jsonp("http://ipinfo.io/json?callback=JSON_CALLBACK"); }; service.getCurrentWeather = function(city) { var ...

Troubleshooting: Custom JQuery function not functioning as expected

I am currently facing an issue with the jQuery in my website while trying to implement a portfolio element. It seems to be related to the changePortfolio() function, but I am unsure of how to resolve it. $('.projects a[href^="#"]').on('clic ...

Ensure the initial word (or potentially all words) of a statement is in uppercase in Angular 2+

Struggling with capitalizing words in an Angular 2 template (referred to as view) led to an error in the console and the application failing to load, displaying a blank page: Error: Uncaught (in promise): Error: Template parse errors: The pipe 'c ...

Issue with EaselJS: mouse events are no longer functional

I'm currently working on adding a touch animation using the EaselJs library. Interestingly, when I load an image from a local folder, all mouse events work as expected, such as onPress. However, things take a different turn when I opt to use an imag ...

Linking Two HTML Components in Angular 4 with Identical Values

Recently, I've started working with Angular and encountered an issue. In a table row, the value item.md_id is bound like this: <tr *ngFor="let item of driverData"> <td class="align-right" id="md_id" [(ngModel)]="item.md_id" name="driverId ...