Javascript:在没有 base64-dataURL 的情况下从自定义 API 将许多图像加载到 DOM

Javascript: Loading many images into DOM from a custom API without base64-dataURLs

Contextxt:我目前正在使用 Angular 和用 Silex 编写的 API 构建 web-app。

我遇到了以下情况:

很好,我想,我做了 API 所以它返回了 base64 编码的图像。很容易。将这个 base64 编码的数据设置为图像源更简单:src = "data:image/jpeg;base64," + response;。这是使用 ngSrc 完成的,使其有点异步。灯箱使用 anchor-tag 的 href 从中加载图像(为此我使用 Colorbox),因此每张照片我有两个相当大的 base64-dataURL。

然而,这会导致严重的问题。不是立即只有一张图片,而是图片数量开始增加时。浏览器选项卡开始需要越来越多的内存,因为 base64-URL 保留在 DOM.

我为此创建了一个临时解决方法,方法是创建一个自定义 Silex 控制器,该控制器不从 headers 而是从 query-string 读取其令牌。这允许我将图像源设置为:src = "http://api/img/1?token=" + token;。 data-URLs 的问题和他们的记忆饥饿问题已经一去不复返了。

但是,将来 API 很可能会开始要求 HTTP 基本身份验证来获取图像。并且基本身份验证凭据不能通过查询字符串传递。它们需要 headers 才能运行。所以我的解决方法将不再有效。因此,这是一个真正的临时解决方法。

虽然我不完全确定如何解决这个问题。需要通过 Ajax-call 加载图像才能添加自定义 headers。整个事情必须是异步的,所以加载尽可能快。加载图像后,它不应占用内存,或者至少不会占用太多内存以保持页面性能,无论显示多少图像。

我一直在研究将基于 base64 的图像加载到 canvas 元素上。像这样:

$scope.loadThumbnails = function() {
  $scope.photos.forEach(function($photo){
    $photo.canvas_th = document.querySelector('canvas#' + $photo.id + '_th');

    var request = $http({                                                                               
      method: "GET",                              
      url: [URL]                                     
    });                                                                                                 

    var fetchThumbnailSuccess = function(response) {                                                    
      console.debug("Fetched thumbnail with id " + $photo.id);

      // Get drawing context
      var ctx = $photo.canvas_th.getContext("2d");

      // Create image with onload drawing to context
      var img = new Image();
      img.onload = function() {
        ctx.drawImage(img, 0, 0);
      }

      // Add data to image object, triggering the onload function which in turn draws the image to the context
      img.src = 'data:image/jpeg;base64,' + response;
    }                                                                                                   
    request.success(fetchThumbnailSuccess);                                                             

    var fetchThumbnailFailure = function(response) {                                                    
      console.error("Failed fetching thumbnail with id " + $photo.id);                                
      console.debug(response);                                                                        
    }                                                                                                   
    request.error(fetchThumbnailFailure);                                                               
  });                                                                                                     
}

但是我不确定这是否会并且保持更高的性能。然而,我确信其他人以前必须处理过这样的情况。我忽略了什么吗?做错了什么?我很想就此获得一些帮助,因为我目前仍坚持使用 not-so-fancy 解决方法...有人吗?

Canvas 使用与 img 元素一样多的内存来显示图像,因此使用 canvas 不会帮助您解决内存问题。

自从您累积编码 urls 来存储图像数据以来,您就会遇到不断增加的内存需求。

考虑到您当前灯箱的局限性,"rolling your own" 可能会给您带来更好的效果。

如何只为您的初始显示提供缩略图,然后将单个全尺寸 img 元素的 .src 属性 更改为所选缩略图的 url。

这样一来,您只需为缩略图显示和一张全尺寸图像占用内存。让浏览器缓存全尺寸图像,这样如果您的用户重新查看以前的全尺寸图像,它将快速从缓存中获取而不是重新下载。