【问题标题】:Javascript: Loading many images into DOM from a custom API without base64-dataURLsJavascript:从没有 base64-dataURLs 的自定义 API 将许多图像加载到 DOM
【发布时间】:2015-05-20 17:23:54
【问题描述】:

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

我遇到以下情况:

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

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

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

我为此创建了一个临时解决方法,方法是创建一个自定义 Silex 控制器,该控制器不从标头中读取其令牌,而是从查询字符串中读取。这使我可以将图像源设置为:src = "http://api/img/1?token=" + token;。数据 URL 及其内存不足的问题已经一去不复返了。

但是,在未来,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);                                                               
  });                                                                                                     
}

但我不确定这是否会并保持更高的性能。然而,我确信其他人以前必须处理过这样的情况。我忽略了什么吗?做一些完全错误的事情?我很想在这方面得到一些帮助,因为我目前被我不那么花哨的解决方法困住了......有人吗?

【问题讨论】:

    标签: javascript canvas base64


    【解决方案1】:

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

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

    考虑到您当前灯箱的局限性,也许“自己动手”会给您带来更好的性能。

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

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

    【讨论】:

    • 感谢您的建议。我用谷歌搜索了更多,发现像我目前实现的那样保护对静态资源的访问并不少见(将令牌添加到查询参数而不是标题)。我认为我将不得不放弃使用 HTTP 基本身份验证来保护所有内容的愿望,并保留我当前的解决方法,因为它运行完美,并允许浏览器通过缓存所有内容来发挥其魔力。像滚动动态加载这样的东西会进一步提高性能。
    猜你喜欢
    • 2017-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多