Правильный способ проверить, является ли 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)
статический метод должен выполнить следующие шаги:
- Пусть это результат разбора.
- Если схема не "
blob
", возвращаться.- Пусть будет источником
url record
.- Пусть будет текущий объект настроек .
- Если его происхождение не совпадает с происхождением '', вернитесь.
- Удалите запись из хранилища URL-адресов BLOB-объектов для:
- Пусть store будет хранилищем URL-адресов больших двоичных объектов пользовательского агента;
- Пусть строка URL будет результатом сериализации URL.
- Удалить магазин
url string
.
- Удалить все записи из
map
которые соответствуют данному условию (т.е. равныurl
)- ... или ничего не делать, если никто этого не делает.
Кроме того, обратите внимание, что в спецификации также отмечается, что:
Это означает, что вместо того, чтобы выдать какую-либо ошибку, попытка отозвать незарегистрированный URL-адрес завершится неудачей . В этом случае пользовательские агенты могут отобразить сообщение на консоли ошибок.
Следовательно, мы можем сделать вывод:
- Если схема URI равна , или если
string
URL-адрес начинается с , тогда это URL -адрес BLOB-объекта .- ...и поэтому он может быть отозван сценарием (из того же источника), вызывающим .
- Если
URL.revokeObjectURL(url)
используется с неверным URL-адресом, то ничего плохого не произойдет (например, выброшенныйError
или другое исключение времени выполнения). Примеры недействительных URL-адресов:- URL-адреса, не относящиеся к схеме (в результате шага 2)
- URL-адреса другого происхождения (из-за шага 5)
- Уже отозванные ObjectURL(в связи с шагом 6.3.2)
- Синтаксически допустимые URL-адреса одного и того же происхождения, содержащие поддельные UUID (также из-за шага 6.3.2).
Приложение: регулярное выражение для сопоставления URL-адресов объектов:
Спецификация API веб-файлов также предписывает определенный формат URI, что означает, что они также могут быть сопоставлены с помощью регулярного выражения (при условии, что спецификация не изменится):
- Пусть это пустая строка.
- Добавьте строку "
blob:
" к .- Позволять
settings
быть текущим объектом настроек- Позволять
origin
быть источником настроек.- Пусть это сериализация источника ASCII.
- Если
serialized
имеет значение «null», установите для него значение, определенное реализацией.- Добавить сериализованный в .
- Добавить
U+0024
СОЛИДУС (/) до .- Создайте UUID RFC4122 в виде строки и добавьте его в файл .
- Возвращаться
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 );
}
Демо: