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

时间:2015-05-20 17:23:55

标签: javascript canvas base64

Contexxt:我目前正在开发一个使用Angular构建的Web应用程序,其中包含用Silex编写的API。

我遇到以下情况:

  • 包含多达数百个可点击缩略图的Angular页面。点击后,灯箱插件会打开全尺寸图片
  • 需要自定义令牌标头加载每张图片的API

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

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

我已经通过创建一个自定义Silex控制器为此创建了一个临时解决方法,该控制器不会从标头读取标记,而是从查询字符串读取标记。这允许我将图像源设置为:src = "http://api/img/1?token=" + token;。数据网址及其内存饥饿问题已经一去不复返了。

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

我不完全确定如何解决这个问题。需要通过Ajax调用加载图像才能添加自定义标头。整个事情必须是异步的,所以加载尽可能快。加载图像后,无论显示多少图像,都不应占用内存,或者至少不要占用页面效果。

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

但我不确定这是否会保持更高性能。但我确信其他人必须先应对这种情况。我忽略了什么吗?做错了什么?我很想得到一些帮助,因为我目前仍然坚持使用我那不那么花哨的解决方法......任何人?

1 个答案:

答案 0 :(得分:1)

Canvas使用尽可能多的内存来显示图像作为img元素,因此使用canvas不会对你的内存问题有所帮助。

只要您正在累积已编码的网址来存储图像数据,就会遇到不断增加的内存需求。

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

如何为初始显示提供thumnails,然后将单个完整大小的img元素的.src属性更改为所选缩略图的URL。

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