【问题标题】:How do I abort image <img> load requests without using window.stop()如何在不使用 window.stop() 的情况下中止图像 <img> 加载请求
【发布时间】:2011-10-19 06:28:04
【问题描述】:

我有一个很长的页面,当用户滚动浏览时会动态加载图像。

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

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

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

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

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

【问题讨论】:

  • 也许停止加载是错误的方法?例如,您能否在 开始 加载图像之前等待 200 毫秒,并在超时结束时检查图像是否仍在视图中?
  • 这可能会有所帮助,但如果用户在某处暂停 200 毫秒并触发一堆图像加载,然后移动到其他地方,所有这些图像仍会在浏览器排队查看新图像之前加载.在之前的图像完成加载并且队列到达当前正在查看的图像之前,用户可能会盯着空白区域一段时间。

标签: javascript jquery html ajax image


【解决方案1】:

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

  1. 如果您的用户疯狂地上下滚动页面,他/她会预料到一些加载延迟。
  2. 在开始加载页面的一部分之前有一个超时延迟(例如:200 毫秒)是完全可以接受的,并且在您的页面上的 200 毫秒间隔之后会停止和跳转多少次?即使它发生了,它又回到了第 1 点
  3. 您的图像有多大?即使是速度较慢的服务器也可以每秒提供大约几十个 3Kb 的缩略图。如果您的网站有更大的图像,请考虑使用带有lightBox 等组件的低分辨率和高分辨率图像

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

** 编辑 **

这是一个想法:

  1. 您的页面应显示DIV 容器,其宽度和高度与预期的图像大小相同(使用 CSS 设置样式)。在每个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();
       }
    };
    
    });
    

【讨论】:

  • 我们的 UI 提倡略读,用户希望照片在滚动时加载,并且当用户将手指移回滚动轮/触控板的顶部时通常会发生 200 毫秒的延迟,即使意图是连续滚动也是如此.每次偶然的暂停都会导致照片加载,并且在针对低带宽场景进行设计时,由于加载队列不断变大,可能会导致用户等待很长时间。话虽如此,您说停止负载是错误的是对的,感谢您向我展示src 问题。我想我只需要更加了解我加载的照片数量和时间。
  • 只需为滚动区域使用更好的压缩图像,在悬停时使用更高质量的图像,或者如果用户停止更长的时间(在队列中一次加载一张图像
  • 如何在滚动条上加载图像?
  • Empty img src 不再是问题,如上面链接博客文章末尾所述:更新(2009 年 12 月 2 日):似乎 已被修补火狐 3.5 (bug 444931)
【解决方案2】:

好吧,我的想法:

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

2) 你可以中止 XHR

我写了一个小型服务器,用 express 模拟巨大的图像下载(它实际上只等待 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>

【讨论】:

    【解决方案3】:

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

    1) 标记您要加载的图像

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

    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) 取消将那些加载到屏幕外

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

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

    [1]。 Check if element is visible after scrolling

    [2]。 Abort Ajax requests using jQuery

    【讨论】:

    • 此方法不起作用,因为 .each 只会附加一次。您需要一个 onscroll 事件来重新检查图像可见性,理想情况下,这不应该是遍历 dom 中所有图像的循环,因为性能会变差。
    【解决方案4】:

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

    1) 创建一个新的 iframe

    2) iframe 内部有开始加载图片的脚本,一旦加载完毕,调用.parent 的方法

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

    【讨论】:

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

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

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

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

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

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

      干杯!

      【讨论】:

        【解决方案6】:

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

        这可能有点过头了。

        【讨论】:

          【解决方案7】:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-05-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-05-03
            • 1970-01-01
            • 2012-10-19
            相关资源
            最近更新 更多