Правильный способ проверить, является ли URL результатом вызова createObjectURL?

У меня есть ситуация, когда пользователь устанавливает изображение либо на URL, либо с помощью байтов, которые преобразуются в URL объекта BLOB-объекта. Насколько я понимаю, чтобы предотвратить утечку ресурсов, я должен освобождать URL-адреса объектов BLOB-объектов при их изменении, но я не уверен, правильно ли я проверяю тип старого URL-адреса. В настоящее время я делаю это, просто проверяя, начинается ли URL с 'blob:', Вот пример игрушечной функции, которая демонстрирует, что она действительно работает:

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);
    }
}

Это правильный способ сделать это? Есть ли лучший способ сделать это?

Отмечу, что пробовал звонить URL.revokeObjectURL для строк, которые не являются объектными URL-адресами и, кажется, работают нормально, поэтому мне также не ясно, насколько важно, чтобы я правильно определил, должен ли URL-адрес быть освобожден.

Примечание: это сценарий TypeScript, но я думаю, что вопрос одинаково действителен в Javascript, поэтому я отметил оба.

2 ответа

Вы правы, я думаю, что в настоящее время другого пути нет вообще.

Это правильный способ сделать это?

Да.


Более детально:

В настоящее время я просто проверяю, начинается ли URL с'blob:'.

Это правильный способ сделать это? Есть ли лучший способ сделать это?

Мы можем это узнать наверняка, ознакомившись со спецификацией, которая определяет, как должно работать

(выделено мной, ссылки на подинструкции встроены)

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

The revokeObjectURL(url)статический метод должен выполнить следующие шаги:

  1. Пусть это результат разбора.
  2. Если схема не " blob", возвращаться.
  3. Пусть будет источникомurl record.
  4. Пусть будет текущий объект настроек .
  5. Если его происхождение не совпадает с происхождением '', вернитесь.
  6. Удалите запись из хранилища URL-адресов BLOB-объектов для:
    1. Пусть store будет хранилищем URL-адресов больших двоичных объектов пользовательского агента;
    2. Пусть строка URL будет результатом сериализации URL.
    3. Удалить магазинurl string.
      1. Удалить все записи изmapкоторые соответствуют данному условию (т.е. равныurl)
      2. ... или ничего не делать, если никто этого не делает.

Кроме того, обратите внимание, что в спецификации также отмечается, что:

Это означает, что вместо того, чтобы выдать какую-либо ошибку, попытка отозвать незарегистрированный URL-адрес завершится неудачей . В этом случае пользовательские агенты могут отобразить сообщение на консоли ошибок.

Следовательно, мы можем сделать вывод:

  • Если схема URI равна , или еслиstringURL-адрес начинается с , тогда это URL -адрес BLOB-объекта .
    • ...и поэтому он может быть отозван сценарием (из того же источника), вызывающим .
  • ЕслиURL.revokeObjectURL(url)используется с неверным URL-адресом, то ничего плохого не произойдет (например, выброшенныйErrorили другое исключение времени выполнения). Примеры недействительных URL-адресов:
    • URL-адреса, не относящиеся к схеме (в результате шага 2)
    • URL-адреса другого происхождения (из-за шага 5)
    • Уже отозванные ObjectURL(в связи с шагом 6.3.2)
    • Синтаксически допустимые URL-адреса одного и того же происхождения, содержащие поддельные UUID (также из-за шага 6.3.2).

Приложение: регулярное выражение для сопоставления URL-адресов объектов:

Спецификация API веб-файлов также предписывает определенный формат URI, что означает, что они также могут быть сопоставлены с помощью регулярного выражения (при условии, что спецификация не изменится):

  1. Пусть это пустая строка.
  2. Добавьте строку "blob:" к .
  3. Позволятьsettingsбыть текущим объектом настроек
  4. Позволятьoriginбыть источником настроек.
  5. Пусть это сериализация источника ASCII.
  6. Еслиserializedимеет значение «null», установите для него значение, определенное реализацией.
  7. Добавить сериализованный в .
  8. ДобавитьU+0024СОЛИДУС (/) до .
  9. Создайте UUID RFC4122 в виде строки и добавьте его в файл .
  10. Возвращатьсяresult
  • Пример URL-адреса большого двоичного объекта, который может быть создан с помощью этого алгоритма:blob:https://example.org/40a5fb5a-d56d-4a33-b4e2-0acf6a8e5f64.

СледовательноRegExpв JS это будет так (на основе этого RegExp для соответствия строкам происхождения HTTP):

      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 );
}

Демо:

Другие вопросы по тегам