【问题标题】:Adding img.crossOrigin = "*" interferes with img.complete添加 img.crossOrigin = "*" 会干扰 img.complete
【发布时间】:2020-08-24 17:30:21
【问题描述】:

我有一个读取地图图块图像的函数。我想跟踪某个图像是否已经被缓存。我正在使用来自this thread的这个功能:

function is_cached(src) {
    var image = new Image();
    image.src = src;

    return image.complete;
}

这工作得很好。但后来我需要做一些图像处理。为了将图像数据复制到画布并逐像素处理,我需要使用CanvasRenderingContext2D.drawImage(image, 0, 0)。但它让我感到困扰的是一个跨域错误。所以我可以添加一个image.crossOrigin = "*",它解决了这个问题,我可以写到画布上并进行我需要的图像处理。那一点看起来像这样:

  imageOutput.crossOrigin = "*"
  var demCtx;
  imageOutput.onload = function(){
    var c = document.createElement('canvas')
    c.width = c.height = 256
    demCtx = c.getContext('2d')
    demCtx.drawImage(imageOutput, 0, 0)
    var imageData = demCtx.getImageData(0, 0, 256, 256)
  }

出现的问题是,每次我运行包含这两位代码的较大函数时,is_cached 函数每次都返回 false,除了第一次。但我知道,即使 is_cached 返回 false,图像也确实被缓存了,因为它们以 0 延迟加载(而不是在调用新图像时需要一些时间从服务器获取它)。

为什么.crossOrigin = "*" 会干扰图像的.complete 状态?

这发生在 ObservableHQ 笔记本中。这可能与它有关吗? ObservaleHQ 有时会变得很奇怪。

ObservableHQ Notebook with the problem

您可以在底部的getTileUrl 单元格中找到此代码。这个笔记本还没写完。点击提交更改到输入的地图后,您可以在Tile Previously Cached 行看到缓存状态。

感谢阅读。

【问题讨论】:

  • is_cached 函数被破解。获取图像是异步的,即使在缓存时也是如此。你最好把它扔掉。为什么你需要知道你的图片是否被缓存了?
  • 诚实的问题:为什么它是 hack? is_cached 函数在另一个问题中是一个广受欢迎的答案,它为我提供了我需要的确切/预期行为,直到我引入 crossOrigin = "*" 行。回答您的 Q - 简短回答:更好地了解缓存的工作原理。长答案:我想在我正在编写的应用程序中使用磁贴图像作为数据源,并且我正在尝试找到预加载磁贴的最佳方法,并将它们的数据待机以提高性能。我不确定缓存是否足够,或者我是否应该使用另一种临时的浏览器内存储方法
  • 查看该答案下的 cmets。它不会告诉您图像是否被缓存,但它是否已经被当前文档加载。现在规范还要求在微任务中完成获取操作系统,以便在没有同步触发任何内容的情况下无法设置 srcset 和 crossorigin。而且您可能还没有足够的特权来查看它,但是这个答案也几乎没有应得的反对票。对于您想要的,在应用程序的开头预加载所有资产,并存储由这些图像制成的 ImageBitmap,这是最高效的方式。
  • 感谢您的解释。我有一种感觉,依赖缓存可能不是跟踪我的图块的最佳方法,我想手动进行。我修改了我的笔记本,如果它们尚未保存,则将它们以 ImageBitaps 的形式保存到对象中。然后我只需要获取以前未保存的图块。我知道如何使用ImageBitMap 写入画布并从那里获取像素数据。考虑到我想稍后逐个像素地访问像素数据,您认为保存ImageBitmaps 或保存画布ImageData Uint8ClampedArray 会更高效吗?
  • ;-) ImageBitmap 对象本身非常小,它只有自己的widthheight,这就是你所有的sizeof 度量(以及它可以度量的所有)。然而,这个对象只是我们作为作者可以获得的冰山一角。在底层,它链接到浏览器将存储在内存中的实际图像位图。要检查这个位图的大小,你需要使用浏览器的开发工具,甚至你的操作系统内存管理工具,但是 256*256 的位图肯定会高于 40 字节 ;-)

标签: javascript image-processing caching canvas observablehq


【解决方案1】:

也许 fetch api 可以使用参数{cache:"force-cache"} 强制缓存,但是应该按预期缓存图像。您可以获取图像并将其 blob 作为图像源传递。

替换您的 imageOutput.src
    imageOutput.src = URL.createObjectURL(await fetch(imageUrl, {cache:"force-cache"}).then(r => r.blob()));

让你的 getTileURL 函数 async 因为我们必须等待 fetch 和 blob 准备好作为图像源传递

  async function getTileURL(latArg, lngArg, zoomArg) {

使用 devtools 检查网络并查看来自磁盘缓存的平铺图像

编辑:

只需尝试您的原始代码并通过 devtools 检查网络。切片图像按预期缓存。所以不需要破解 fetch blob src。

【讨论】:

  • 使用我的原始代码,如果我取出crossOrigin 行,那么当尝试从缓存中已经存在的图像的URL 将src 分配给图像时,没有新的网络请求完全是制作出来的。新的网络请求仅针对以前未获取的图块显示。但是当我重新添加crossOrigin 时,每个图块请求都是一个新请求——“大小”列给出了实际大小,而不是“来自缓存”。但是之前获取的图像加载没有延迟,就好像它们来自缓存一样。这就是问题 - 为什么crossOrigin 会影响浏览器缓存资源的方式?
猜你喜欢
  • 2021-02-24
  • 2016-08-12
  • 1970-01-01
  • 1970-01-01
  • 2017-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-10
相关资源
最近更新 更多