在 Javascript 中加载图像时 iPad/iPhone 浏览器崩溃 [英] iPad/iPhone browser crashing when loading images in Javascript

查看:34
本文介绍了在 Javascript 中加载图像时 iPad/iPhone 浏览器崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 Safari 中构建一个模仿 iPad 照片应用程序的图片库.它工作得很好,除了一旦我通过将它们添加到 DOM 或创建新的 Image 对象来加载超过 6MB 左右的图像,新图像要么停止加载,要么浏览器崩溃.这个问题非常普遍(其他人都遇到了同样的限制),我已经排除了我的 Javascript 代码是罪魁祸首.

I'm trying to build an image gallery in Safari that mimics the iPad photo app. It works perfectly, except that once I load more than 6MB or so worth of images either by adding them to the DOM or creating new Image objects, new images either stop loading or the browser crashes. This problem is widespread enough (with everyone else hitting up against the same limit) that I've ruled out my Javascript code as the culprit.

鉴于您可以在一个元素中或通过浏览器内的媒体播放器流式传输超过几 MB 的内容,此限制似乎没有必要,应该有某种解决方法可用.也许是通过释放内存或其他方式.

Given that you can stream much more than a few MB in a element or through the in-browser media player, this limit seems unnecessary, and there should be some kind of workaround available. Perhaps by freeing up memory or something else.

我也遇到过这个UIWebView 参考.

JavaScript 分配也被限制为 10 MB.如果 JavaScript 的总内存分配超过此限制,Safari 将引发异常."

"JavaScript allocations are also limited to 10 MB. Safari raises an exception if you exceed this limit on the total memory allocation for JavaScript."

这与我所看到的相当吻合.是否可以在 Javascript 中释放对象,或者 Safari/UIWebView 是否保持运行总数并且永不放手?或者,是否有任何解决方法可以通过另一种方式加载数据而不占用这 10MB?

Which matches what I'm seeing fairly well. Is it possible to deallocate objects in Javascript, or does Safari/UIWebView keep a running total and never lets go? Alternately, is there any workaround to load in data another way that doesn't eat up this 10MB?

推荐答案

更新:我认为有一种更简单的方法可以做到这一点,具体取决于您的应用程序.如果您只有一个 <img> 元素或 Image 对象(或者可能是两个,例如这个"图像和下一个"图像),而不是多个图像如果你需要动画或过渡),只需更新 .src.width.height 等,你不应该接近10MB 限制.如果您想做轮播应用程序,则必须首先使用较小的占位符.您可能会发现这种技术可能更容易实现.

Update: I think there's an even easier way to do this, depending on your application. Instead of having multiple images, if you simply have one <img> element or Image object (or maybe two, like a 'this' image and a 'next' image if you need animations or transitions) and simply update the .src, .width, .height and so on, you should never get near the 10MB limit. If you wanted to do a carousel application, you'd have to use smaller placeholders first. You might find this technique might be easier to implement.

我想我实际上可能已经找到了解决方法.

I think I may actually have found a work-around to this.

基本上,您需要进行一些更深入的图像管理,并明确缩小您不需要的任何图像.您通常会通过使用 document.removeChild(divMyImageContainer)$("myimagecontainer").empty() 或您有什么来做到这一点,但在 Mobile Safari 上这样做绝对没有;浏览器根本不会释放内存.

Basically, you'll need to do some deeper image management and explicitly shrink any image you don't need. You'd normally do this by using document.removeChild(divMyImageContainer) or $("myimagecontainer").empty() or what have you, but on Mobile Safari this does absolutely nothing; the browser simply never deallocates the memory.

相反,您需要更新图像本身,使其占用很少的内存;您可以通过更改图像的 src 属性来实现.我所知道的最快方法是使用 数据 URL.所以不要这样说:

Instead, you need to update the image itself so it takes up very little memory; and you can do that by changing the image's src attribute. The quickest way I know of to do that is to use a data URL. So instead of saying this:

myImage.src="/path/to/image.png"

...改为这样说:

myImage.src="data:image/gif;base64,AN_ENCODED_IMAGE_DATA_STRING"

下面是一个测试来证明它的工作原理.在我的测试中,我的 750KB 大图像最终会杀死浏览器并停止所有 JS 执行.但是在重置 src 后,我已经能够加载图像实例超过 170 次.代码如何工作的解释也如下所示.

Below is a test to demonstrate it working. In my tests, my large 750KB image would eventually kill the browser and halt all JS exectution. But after resetting src, I"ve been able to load in instances of the image over 170 times. An explanation of how the code works is below as well.

var strImagePath = "http://path/to/your/gigantic/image.jpg";
var arrImages = [];
var imgActiveImage = null
var strNullImage = "data:image/gif;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7";
var intTimesViewed = 1;
var divCounter = document.createElement('h1');
document.body.appendChild(divCounter);

var shrinkImages = function() {
    var imgStoredImage;
    for (var i = arrImages.length - 1; i >= 0; i--) {
        imgStoredImage = arrImages[i];
        if (imgStoredImage !== imgActiveImage) {
            imgStoredImage.src = strNullImage;
        }
    }
};
var waitAndReload = function() {
    this.onload = null;
    setTimeout(loadNextImage,2500);
};
var loadNextImage = function() {
    var imgImage = new Image();
    imgImage.onload = waitAndReload;
    document.body.appendChild(imgImage);
    imgImage.src = strImagePath + "?" + (Math.random() * 9007199254740992);
    imgActiveImage = imgImage;
    shrinkImages()
    arrImages.push(imgImage);
    divCounter.innerHTML = intTimesViewed++;
};
loadNextImage()

编写此代码是为了测试我的解决方案,因此您必须弄清楚如何将其应用于您自己的代码.代码分为三部分,我将在下面解释,但唯一真正重要的部分是 imgStoredImage.src = strNullImage;

This code was written to test my solution, so you'll have to figure out how to apply it to your own code. The code comes in three parts, which I will explain below, but the only really important part is imgStoredImage.src = strNullImage;

loadNextImage() 只是加载一个新图像并调用 shr​​inkImages().它还分配了一个 onload 事件,用于开始加载另一个图像的过程(错误:我应该稍后清除此事件,但我没有).

loadNextImage() simply loads a new image and calls shrinkImages(). It also assigns an onload event which is used to begin the process of loading another image (bug: I should be clearing this event later, but I'm not).

waitAndReload() 只是为了让图像有时间显示在屏幕上.移动版 Safari 速度非常慢并且显示大图像,因此在图像加载后需要时间来绘制屏幕.

waitAndReload() is only here to allow the image time to show up on the screen. Mobile Safari is pretty slow and displaying big images, so it needs time after the image has loaded to paint the screen.

shr​​inkImages() 遍历所有先前加载的图像(活动图像除外)并将 .src 更改为 dataurl 地址.

shrinkImages() goes through all previously loaded images (except the active one) and changes the .src to the dataurl address.

我在这里为 dataurl 使用了一个文件夹图像(这是我能找到的第一个 dataurl 图像).我只是在使用它,所以您可以看到脚本正在运行.您可能想要使用透明的 gif,因此请改用此数据 url 字符串:data:image/gif;base64,R0lGODlhAQABAIAAAP//wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==

I'm using a file-folder image for the dataurl here (it was the first dataurl image I could find). I'm using it simply so you can see the script working. You'll probably want to use a transparent gif instead, so use this data url string instead: data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==

这篇关于在 Javascript 中加载图像时 iPad/iPhone 浏览器崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆