Javascript 如何在不使用 window.stop() 的情况下中止图像 <img> 加载请求

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6929662/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 23:48:59  来源:igfitidea点击:

How do I abort image <img> load requests without using window.stop()

javascriptjqueryhtmlajaximage

提问by Evan

I have a very long page that dynamically loads images as users scroll through.

我有一个很长的页面,可以在用户滚动时动态加载图像。

However, if a user quickly scrolls away from a certain part of the page, I don't want the images to continue loading in that now out-of-view part of the page.

但是,如果用户从页面的某个部分快速滚动离开,我不希望图像继续加载到页面现在不在视图中的部分。

There are lots of other requests happening on the page simultaneously apart from image loading, so a blunt window.stop() firing on the scroll event is not acceptable.

除了图像加载之外,页面上还会同时发生许多其他请求,因此在滚动事件上触发的生硬 window.stop() 是不可接受的。

I have tried removing & clearing the img src attributes for images that are no longer in view, however, since the request was already started, the image continues to load.

我尝试删除并清除不再可见的图像的 img src 属性,但是,由于请求已经开始,图像继续加载。

Remember that the image src was filled in as the user briefly scrolled past that part of the page. Once past though, I couldn't get that image from stop loading without using window.stop(). Clearing src didn't work. (Chrome & FF)

请记住,当用户短暂地滚动经过页面的那部分时,图像 src 已被填充。但是,一旦过去,如果不使用 window.stop(),我就无法从停止加载中获取该图像。清除 src 不起作用。(铬 & FF)

Similar posts I found that get close, but don't seem to solve this problem:

我发现类似的帖子很接近,但似乎没有解决这个问题:

采纳答案by Yanick Rochon

What you are trying to do is the wrong approach, as mentioned by nrabinowitz. You can't just "cancel" the loading process of an image (setting the srcattribute to an empty string is not a good idea). In fact, even if you could, doing so would only make things worst, as your server would continually send data that would get cancelled, increasing it's load factor and slow it down. Also, consider this:

正如nrabinowitz所提到的,您尝试做的是错误的方法。您不能只是“取消”图像的加载过程(将src属性设置为空字符串不是一个好主意)。事实上,即使你可以,这样做只会让事情变得更糟,因为你的服务器会不断发送会被取消的数据,增加它的负载因子并减慢它的速度。另外,请考虑:

  1. if your user scroll frenetically up and down the page, he/she will expect some loading delays.
  2. having a timeout delay (ex: 200 ms) before starting to load a portion of the page is pretty acceptable, and how many times will one stop and jump after 200 ms interval on your page? Even it it happens, it comes back to point 1
  3. how big are your images? Even a slow server can serve about a few tens of 3Kb thunbnails per second. If your site has bigger images, consider using low and hi resolution images with some components like lightBox
  1. 如果您的用户疯狂地上下滚动页面,他/她会期望一些加载延迟。
  2. 在开始加载页面的一部分之前有一个超时延迟(例如:200 毫秒)是可以接受的,在您的页面上的 200 毫秒间隔后,一个人会停止和跳跃多少次?即使它发生了,它也会回到第 1 点
  3. 你的图片有多大?即使是速度较慢的服务器,每秒也可以提供大约几十个 3Kb 的缩略图。如果您的网站有更大的图像,请考虑使用带有LightBox 等组件的低分辨率和高分辨率图像

Often, computer problems are simply design problems.

通常,计算机问题只是设计问题。

** EDIT**

**编辑**

Here's an idea :

这是一个想法:

  1. your page should display DIVcontainers with the width and height of the expected image size (use CSS to style). Inside of each DIV, add an link. For example :

    <div class="img-wrapper thumbnail">
       <a href="http://www.domain.com/path/to/image">Loading...</a>
    </div>
    
  2. Add this Javascript (untested, the idea is self describing)

    $(function() {
    
    var imgStack;
    var loadTimeout;
    
    $(window).scroll(function() {
       imgStack = null;
       if (loadTimeout) clearTimeout(loadTimeout);
    
       loadTimeout = setTimeout(function() {
    
          // get all links visible in the view port
          // should be an array or jQuery object
          imgStack = ...
    
          loadNextImage();
       }, 200);                // 200 ms delay
    });
    
    function loadNextImage() {
       if (imgStack && imgStack.length) {
          var nextLink = $(imgStack.pop());   // get next image element
    
          $('<img />').attr('src', nextLink.attr('href'))
            .appendTo(nextLink.parent())
            .load(function() {
               loadNextImage();
            });
    
          // remove link from container (so we don't precess it twice)
          nextLink.remove();
       }
    };
    
    });
    
  1. 您的页面应显示DIV具有预期图像大小的宽度和高度的容器(使用 CSS 设置样式)。在 each 里面DIV,添加一个链接。例如 :

    <div class="img-wrapper thumbnail">
       <a href="http://www.domain.com/path/to/image">Loading...</a>
    </div>
    
  2. 添加这个 Javascript(未经测试,这个想法是自我描述的)

    $(function() {
    
    var imgStack;
    var loadTimeout;
    
    $(window).scroll(function() {
       imgStack = null;
       if (loadTimeout) clearTimeout(loadTimeout);
    
       loadTimeout = setTimeout(function() {
    
          // get all links visible in the view port
          // should be an array or jQuery object
          imgStack = ...
    
          loadNextImage();
       }, 200);                // 200 ms delay
    });
    
    function loadNextImage() {
       if (imgStack && imgStack.length) {
          var nextLink = $(imgStack.pop());   // get next image element
    
          $('<img />').attr('src', nextLink.attr('href'))
            .appendTo(nextLink.parent())
            .load(function() {
               loadNextImage();
            });
    
          // remove link from container (so we don't precess it twice)
          nextLink.remove();
       }
    };
    
    });
    

回答by Guard

Well, my idea:

嗯,我的想法:

1) initiate an AJAX request for the image, if it succeeds, the image goes to the browser cache, and once you set the 'src' attribute, the image is shown from the cache

1) 对图片发起AJAX请求,如果成功,图片进入浏览器缓存,一旦设置了'src'属性,图片就会从缓存中显示

2) you can abort the XHR

2) 您可以中止 XHR

I wrote a tiny server with express emulating the huge image download (it actually just waits 20 seconds, then returns an image). Then I have this in my HTML:

我写了一个微型服务器,快速模拟巨大的图像下载(它实际上只等待 20 秒,然后返回一个图像)。然后我在我的 HTML 中有这个:

<!DOCTYPE html>
<html>
    <head>
        <style>
            img {
                width: 469px;
                height: 428px;
                background-color: #CCC;
                border: 1px solid #999;
            }
        </style>
    </head>

    <body>
        <img data-src="./img" src="" />
        <br />
        <a id="cancel" href="javascript:void(0)">CANCEL</a>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
        <script>
            $(function () {
                var xhr, img = $('img'), src = img.data('src');

                xhr = $.ajax(src, {
                    success: function (data) { img.attr('src', src) }
                });

                $('#cancel').click(function (){
                    xhr.abort();
                })
            });
        </script>
    </body>
</html>

回答by Jakub M.

You can load your images using ajax calls, and in case that the uses scrolls-out, you can abort the calls.
In jQuery pseudo-code it would be something like that (forgive me mistakes in syntax, it is just an example):

您可以使用 ajax 调用加载图像,如果使用滚出,您可以中止调用。
在 jQuery 伪代码中,它会是这样的(请原谅我的语法错误,这只是一个例子):

1) tag images that you want to load

1) 标记要加载的图像

$(".image").each( function(){
    if ( is_in_visible_area(this) ) { // check [1] for example
        $(this).addClass("load_me");
    } else {
        $(this).addClass("dont_load");
    }
});

2) load images

2)加载图像

ajax_requests = {};

$(".image.load_me").each( function(){
    // load image
    var a = $.ajax({
        url: 'give_me_photos.php',
        data: {img: photo_id},
        success: function(html){
            photo_by_id(photo_id), img.append(html);
        }
    });
    ajax_requests[photo_id] = a;

});

3) cancel loading those out of the screen

3)取消从屏幕加载那些

for( id in ajax_requests ) {
    if ( ! is_in_visible_area(id) ) {
        ajax_requests[id].abort();
    }
}

Of course, add also some checking if the image is already loaded (e.g. class "loaded")

当然,还要添加一些检查图像是否已经加载(例如类“加载”)

[1]. Check if element is visible after scrolling

[1]。滚动后检查元素是否可见

[2]. Abort Ajax requests using jQuery

[2]。使用 jQuery 中止 Ajax 请求

回答by Guard

BTW, another idea that might work:

顺便说一句,另一个可能有效的想法:

1) create a new iframe

1) 创建一个新的 iframe

2) inside of the iframe have the script that starts loading the image, and once it's loaded, call the .parent's method

2) 在 iframe 内部有开始加载图像的脚本,一旦加载,调用.parent's 方法

3) when in need, stop the iframe content loading using .stopon the iframe object

3) 需要时,停止使用.stopiframe 对象加载 iframe 内容

回答by vvohra87

  1. Use a stack to manage ajax requests (means you will have serial loading instead of parallel but it is worth it)

  2. On scroll stop, wait for 300ms and then push all images inside view-area into stack

  3. Every time a user scrolls check if a stack is running. (fyi - you can stop all requests to a particular url instead of killing all ajax calls. also you can use regex so it should not stop any other requests on the page)

  4. If an existing stack is running - pop all the images that are in it except for the top most one.

  5. On all ajax calls - bind beforeSend() event to remove that particular image from the stack

  1. 使用堆栈来管理 ajax 请求(意味着您将使用串行加载而不是并行加载,但这是值得的)

  2. 在滚动停止时,等待 300 毫秒,然后将视图区域内的所有图像推入堆栈

  3. 每次用户滚动检查堆栈是否正在运行。(仅供参考 - 您可以停止对特定 url 的所有请求,而不是终止所有 ajax 调用。您也可以使用正则表达式,因此它不应停止页面上的任何其他请求)

  4. 如果现有堆栈正在运行 - 弹出除最顶部的图像之外的所有图像。

  5. 在所有 ajax 调用中 - 绑定 beforeSend() 事件以从堆栈中删除该特定图像

It is late right now, but we have done something very similar at work - if you need the detailed code let me know.

现在已经晚了,但我们在工作中做了一些非常相似的事情——如果你需要详细的代码,请告诉我。

Cheers!

干杯!

回答by matthewdaniel

Maybe you could serve the image through a php script which would check a field in the the db (or better yet a memcached) that would indicate stop loading. the script would portion up the image into chunks and pause in between each chunk and check if the stop flag for the particular request is. If it is set you send the header with A 204 no content which as soon as the browser gets it will stop receiving.

也许您可以通过 php 脚本提供图像,该脚本将检查 db(或更好的 memcached)中的一个字段,该字段将指示停止加载。该脚本会将图像分成块并在每个块之间暂停并检查特定请求的停止标志是否是。如果设置了,则发送带有 A 204 no content 的标头,一旦浏览器获取它就会停止接收。

This may be a bit over kill though.

不过,这可能有点过头了。

回答by teter

The solution could be a webworker. a webworker can be terminated and with him the connection. But there is a small problem that the webworker uses the limited connections of the browser so the application will be blocked.

解决方案可能是网络工作者。可以终止网络工作者并与他建立连接。但是有一个小问题,webworker 使用浏览器的有限连接,所以应用程序会被阻止。

Right now I'm working on a solution with serviceWorkers - they don't have a connection limit (I hope so)

现在我正在与 serviceWorkers 一起研究解决方案 - 他们没有连接限制(我希望如此)