【问题标题】:Image caching with JS on iPad在 iPad 上使用 JS 缓存图像
【发布时间】:2012-06-29 22:06:17
【问题描述】:

我正在开发一个用于 iPad 的纹理选择器。所以基本上只是一堆图像元素。为了避免图像重新加载和延迟,我在 JS 中缓存和重用 Image 对象。有点像

/**
 * Asynchronous version of memoize for use with callback functions. Asserts
 * that last argument is the callback.
 *
 * @param  {Function} func
 * @return {Function}
 */
 util.memoize.async = function(func) {
    var cache = {};
    return function() {
        var hash = JSON.stringify(arguments);
        var args = Array.prototype.splice.call(arguments, 0);
        var callback = args.pop();
        if (hash in cache) {
            return callback.apply(this, cache[hash]);
        }
        args.push(function() {
            cache[hash] = Array.prototype.splice.call(arguments, 0);
            callback.apply(this, cache[hash]);
        });
        return func.apply(this, args);
    };
};

/**
 * Creates new Image element and calls back with loaded image.
 * @param {string} url
 */
io.GetImage = function(url, callback) {
    var img = new Image();
    img.onload = function() {
        callback(img);
    };
    img.src = url;
};

picker.image_ = util.memoize.async(io.GetImage);

然后,每当我需要图像时,我都会调用picker.image_ 并获取缓存的图像。它在桌面、Chrome、Firefox、Safari 上完美运行,但在 iPad 上,我得到的是空(未加载)图像。这是为什么?我真的很喜欢这种方法,它的表现非常好。

看起来好像 Mobile Safari 从 DOM 中删除了图像数据。会这样吗?

更新:澄清一下,正在加载的数据是动态的,因此它不是 AppCache 的最合适用例。

更新*:没有完全令人满意的答案,这是我的解决方案。请注意,复制方法很慢。

/**
 * Creates new Image element and calls back with loaded image.
 * @param {string} url
 */
var GetImage = function(url, callback) {
    var img = new Image();
    img.onload = function() {
        callback(img);
    };
    img.src = url;
};

/**
 * @param {number} num maximum number of stored images
 */
var ImagePool = function(num) {
    this.limit_ = num;
    this.canvases_ = {};
    this.order_ = [];
};

/**
 * Retrieve image from cache.
 *
 * @param  {string}   url      URL of request image
 * @param  {function(HTMLCanvasElement)} callback
 */
ImagePool.prototype.get = function(url, callback) {
    if (this.canvases_[url] !== undefined) {
        callback(this.copy_(url));
    } else {
        if (this.limit_ && this.order_.length == this.limit_) {
            delete this.canvases_[url];
            this.order_.pop();
        }
        GetImage(realUrl, function(img) {
            var c = document.createElement('canvas');
            c.width = img.width;
            c.height = img.height;
            var ctx = c.getContext('2d');
            ctx.drawImage(img, 0, 0);

            this.canvases_[url] = c;
            this.order_.unshift(url);
            callback(this.copy_(url));
        }.bind(this));
    }
};

/**
 * @param  {string} url
 * @return {HTMLCanvasElement}
 * @private
 */
ImagePool.prototype.copy_ = function(url) {
    var c = document.createElement('canvas'),
        cached = this.canvases_[url];
    c.width = cached.width;
    c.height = cached.height;
    var ctx = c.getContext('2d');
    ctx.drawImage(cached, 0, 0);
    return c;
};

【问题讨论】:

  • 那么为什么不将它保存在 DOM 中并使其不可见呢?
  • 我必须竭尽全力在我的 UI 系统中执行此操作,这绝对不是一个优雅的解决方案(我正在寻找的)。

标签: javascript ipad html caching


【解决方案1】:

我认为使用 HTML 5 离线应用程序缓存可以最好地解决您的问题。您列出要缓存的资源,在用户访问请求这些资源的页面后,它们会被缓存以供以后使用。你仍然需要让你的 UI 等到你的图像被加载,但是一旦它们被加载,你就不必担心它们仅仅因为它们不在 DOM 中而被丢弃(This SO question 建议图像位于 DOM 中,但未显示在屏幕上,也会被删除)。

显然,Safari Mobile 有 5MB 的缓存限制,可以通过要求用户同意扩展它来增加(Source)。 this blog post 中的一条评论表明,此扩展提示在 iOS 4 后即可使用。

有用的链接:

【讨论】:

  • 也许我最终会应用应用程序缓存,这些数据是动态的,我必须不断地向清单推送更新。差点忘了这个alistapart.com/articles/application-cache-is-a-douchebag
  • @skrat - 您绝对需要编辑您的问题以添加图像为动态数据的要求。这改变了很多事情。
  • @skrat - 我只是好奇;为什么你的图片会如此动态?
  • 它是一个用于画布绘制的纹理库。用户生成的。
【解决方案2】:

如果您将 Image 对象直接附加到 DOM,您可能会在删除时丢失它,您可以尝试在删除或附加之前克隆它

function clone(obj) {
  if (null == obj || "object" != typeof obj) return obj;
  var copy = obj.constructor();
  for (var attr in obj) {
    if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
  }
  return copy;
}

【讨论】:

  • 试过了,但这个问题归结为 Mob Safari 的 6 MB 限制。无论是否在 DOM 中。
【解决方案3】:

您是否尝试过在服务器上设置适当的标头并让浏览器管理缓存而不是使用此方案?

【讨论】:

  • 我确实遇到了 Mobile Safari 的限制,到目前为止,我的解决方法是维护图像池,将每个下载的图像渲染到画布上,并在需要时复制它。
【解决方案4】:

我会使用嵌入式图像 src base64 编码。只需检查here

因此,您可以根据需要将数据存储为 JSON 格式的字符串,并在需要时将其取回,如果您从不同的 URL 调用图像,也可以将其保存到 localStorage。

是的,它会给您带来巨大的 html 内容和存储空间,但在您的情况下,这绝对值得。

【讨论】:

    猜你喜欢
    • 2020-05-19
    • 2011-11-28
    • 1970-01-01
    • 2015-05-22
    • 2011-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多