正确检查URL是否是CreateObjectUrl调用的结果



i有一个情况,用户将图像设置为URL或使用转换为blob对象URL的字节。我的理解是,为了防止资源泄漏,我应该在更改斑点对象时释放斑点对象的URL,但是我不确定是否正确检查了旧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的字符串上调用URL.revokeObjectURL,并且似乎可以正常工作,所以我还不清楚我正确确定它有多重要是否需要释放URL。

Note :这是一个打字稿脚本,但我认为该问题在JavaScript中同样有效,因此我已经标记了这两个。

你是对的,我认为目前根本没有其他方法。

这是正确的方法吗?


更详细地:

目前,我正在这样做的方法就是检查URL是否以'blob:'开头。

这是正确的方法吗?有更好的方法吗?

我们可以通过咨询定义URL.revokeObjectURL(url)应如何工作的规范来确定找出答案

(重点是我的,以及对子指导的引用)

https://w3c.github.io/fileapi/#dfn-revokeobjecturl

revokeObjectURL(url)静态方法必须运行以下步骤:

  1. url record是解析url的结果。
  2. 如果url record的方案不是" blob&quort返回。
  3. originurl record的起源。
  4. settings为当前设置对象。
  5. 如果originsettings的起源不同,请返回。
  6. 从Blob URL商店中删除url的条目:
    1. 让商店成为用户代理的blob URL商店;
    2. 令URL字符串为序列化URL的结果。
    3. 删除存储url string
      1. map中删除与给定条件相匹配的所有条目(即相等的url
      2. ... 或者如果没有任何事情。

此外,观察到规格还指出:

这意味着试图撤销未注册的URL而不是抛出某种错误,而是会默默失败。如果发生这种情况,用户代理可能会在错误控制台上显示消息。

因此,我们可以得出结论:

  • 如果URI的方案是blob:,或者string URL以blob:开头,则是 blob url
    • ...因此,它 May 被脚本(在同一来源上)撤销URL.revokeObjectURL(url)
  • 如果URL.revokeObjectURL(url)与无效的URL一起使用,那么(例如抛出的Error或其他运行时异常)都不会发生。无效URL的示例包括:
    • blob:方案URL(由于步骤2)
    • 不同的原始URL(由于步骤5)
    • 已经被撤销的objecturls(由于步骤6.3.2)
    • 语法上有效的,相同的原始blob:包含伪造的UUID的URL(也是由于步骤6.3.2)

附录:匹配blob:对象URL的常规表达:

Web文件API规范还规定了blob: URI的特定格式,这意味着它们也可以通过常规表达RegExp匹配(假设规范不会更改):

  1. result为空字符串。
  2. 附加字符串"blob:result
  3. settings为当前设置对象
  4. origin成为设置的起源。
  5. serialized成为原始的ASCII序列化。
  6. 如果serialized为" null",则将其设置为实现定义的值。
  7. 附加序列化到result
  8. 附加U+0024 Solidus(/)到result
  9. 生成UUID RFC4122作为字符串,并将其附加到result
  10. 返回result
  • 该算法可以生成的BLOB URL的示例是blob:https://example.org/40a5fb5a-d56d-4a33-b4e2-0acf6a8e5f64

因此,JS中的RegExp就是这样(基于此REGEXP以匹配HTTP Origin字符串):

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

演示:

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

最新更新