Javascript:从自定义 API 将许多图像加载到 DOM 中,无需使用 base64-dataURLs

标签 javascript canvas base64

Contextxxt:我目前正在开发一个使用 Angular 构建的 Web 应用程序,并使用 Silex 编写的 API。

我遇到以下情况:

  • 带有多达数百个可点击缩略图的 Angular 页面。单击时,灯箱插件会打开全尺寸图像
  • 需要自定义 token header 来加载每张图片的 API

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

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

我通过创建一个自定义 Silex Controller 为此创建了一个临时解决方法,该 Controller 不从 header 而是从查询字符串读取其 token 。这允许我将图像源设置为:src = "http://api/img/1?token="+ token;。数据 URL 及其内存消耗的问题已经消失。

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

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

我一直在考虑将基于 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);                                                               
  });                                                                                                     
}

但是我不确定这是否会并且保持更高的性能。但我确信其他人以前一定也处理过这样的情况。我是否忽略了什么?做一些完全错误的事情吗?我很想获得一些帮助,因为我目前陷入了不太花哨的解决方法......有人吗?

最佳答案

Canvas 使用与 img 元素一样多的内存来显示图像,因此使用 canvas 将无法解决内存问题。

只要您不断积累编码的网址来存储图像数据,您就会一直面临不断增加的内存需求。

鉴于您当前的灯箱的局限性,也许“滚动您自己的灯箱”会给您带来更好的性能。

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

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

关于Javascript:从自定义 API 将许多图像加载到 DOM 中,无需使用 base64-dataURLs,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30356417/

相关文章:

javascript - 无法从 req.header.authorization 解码 base64

javascript - 为什么 CSS 居中会弄乱 Canvas 鼠标坐标?

javascript - 在这种情况下,document.createElement 或 document.write 哪个更好?

javascript - 验证数组中是否存在元素

javascript - 如何使用 JavaScript 验证帐号?

html - 如何使用 HTML5 Canvas 绘制 donut 的一部分?

html - Jasper Reports - 显示来自 html 源的图像

swift - tiffRepresentation 和 bitmapRepresentation 在 Base64 字符串编码方面的区别?

javascript - Ext.JS 4.2.1 使用 Jasmine 进行单元测试 - 应用程序未定义

javascript - Ember 链接到模型中的下一个对象