【问题标题】:How to cancel a jquery.load()?如何取消 jquery.load()?
【发布时间】:2011-02-18 06:46:05
【问题描述】:

我想取消 .load() 操作,当 load() 没有在 5 秒内返回时。如果是这样,我会显示一条错误消息,例如“抱歉,没有加载图片”。

我所拥有的是……

...超时处理:

jQuery.fn.idle = function(time, postFunction){  
    var i = $(this);  
    i.queue(function(){  
        setTimeout(function(){  
            i.dequeue();
            postFunction();  
        }, time);  
    });
    return $(this); 
};

...初始化错误信息超时:

var hasImage = false;

$('#errorMessage')
    .idle(5000, function() {

        if(!hasImage) {
            // 1. cancel .load()            
            // 2. show error message
        }
    });

...图片加载:

$('#myImage')
     .attr('src', '/url/anypath/image.png')
     .load(function(){
         hasImage = true;
         // do something...
      });

我唯一想不通的是如何取消正在运行的 load()(如果可能的话)。

编辑:

另一种方式:如何防止 .load() 方法在返回时调用它的回调函数?

【问题讨论】:

    标签: jquery image timeout jquery-load


    【解决方案1】:

    如果你想要任何这样的自定义处理,你根本不能使用 jQuery.load() 函数。你必须升级到 jQuery.ajax(),无论如何我都推荐它,因为你可以用它做更多的事情,特别是如果你需要任何类型的错误处理,这是必要的。

    对 jQuery.ajax 使用 beforeSend 选项并捕获 xhr。然后您可以创建回调,它可以在超时后取消 xhr,并根据需要创建回调。

    此代码未经测试,但应该可以帮助您入门。

    var enableCallbacks = true;
    var timeout = null;
    jQuery.ajax({
      ....
      beforeSend: function(xhr) {
        timeout = setTimeout(function() {
          xhr.abort();
          enableCallbacks = false;
          // Handle the timeout
          ...
        }, 5000);
      },
      error: function(xhr, textStatus, errorThrown) {
        clearTimeout(timeout);
        if (!enableCallbacks) return;
        // Handle other (non-timeout) errors
      },
      success: function(data, textStatus) {
        clearTimeout(timeout);
        if (!enableCallbacks) return;
        // Handle the result
        ...
      }
    });
    

    【讨论】:

    • 完整软件,感谢您的帮助!有一件小事要纠正:我不得不将“beforeSend(xhr) {”行替换为“beforeSend: function(xhr) {”
    【解决方案2】:

    您改写后的第二个问题:
    如何取消使用 .load() 方法创建的待处理回调函数?

    您可以取消所有 jquery 回调,通过使用这个“核”选项:

    $('#myImage').unbind('load');
    

    【讨论】:

    • 这在动态创建dom元素时不起作用
    【解决方案3】:

    我认为最简单的做法是直接使用$.ajax。这样你就可以开始一个超时,并从超时设置一个标志,ajax 调用上的处理程序可以检查。超时也可以显示消息或其他任何内容。

    【讨论】:

    • 您好,Pointy,感谢您的回答。我也有同样的想法,但我不想分解这些漂亮的 jQuery 封装处理......
    • 嗯,.load() API 是同步的,就是这样。
    • hmm,我可以将我的问题更改为:如何防止 .load() 方法在返回时调用它的回调函数...
    • 我删除了关于.load() 同步的评论——我不认为它实际上是同步的。对于那个很抱歉。尽管如此,我仍然不知道有什么方法可以告诉 jQuery 中止回调; xhr 对象仍然被掩埋。
    • 可以用ajax直接加载图片吗?其他文章建议只有 Base64 图像数据和 REST 图像服务可以使用 ajax。 jQuery ajax 页面没有提及图像,显示的数据类型有:xml、html、json、jsonp、脚本或文本。因此可以在不创建服务器端处理程序来协助处理的情况下使用 ajax。
    【解决方案4】:

    如果您在加载 JQuery 之后加载此代码,您将能够使用超时参数调用 .load()。

    jQuery.fn.load = function( url, params, callback, timeout ) {
        if ( typeof url !== "string" ) {
            return _load.call( this, url );
    
        // Don't do a request if no elements are being requested
        } else if ( !this.length ) {
            return this;
        }
    
        var off = url.indexOf(" ");
        if ( off >= 0 ) {
            var selector = url.slice(off, url.length);
            url = url.slice(0, off);
        }
    
        // Default to a GET request
        var type = "GET";
    
        // If the second parameter was provided
        if ( params ) {
            // If it's a function
            if ( jQuery.isFunction( params ) ) {
                if( callback && typeof callback === "number"){
                    timeout = callback;
                    callback = params;
                    params = null;
                }else{
                    // We assume that it's the callback
                    callback = params;
                    params = null;
                    timeout = 0;
                }
            // Otherwise, build a param string
            } else if( typeof params === "number"){
                timeout = params;
                callback = null;
                params = null;
            }else if ( typeof params === "object" ) {
                params = jQuery.param( params, jQuery.ajaxSettings.traditional );
                type = "POST";
                if( callback && typeof callback === "number"){
                    timeout = callback;
                    callback = null;
                }else if(! timeout){
                    timeout = 0;
                }
            }
        }
    
        var self = this;
    
        // Request the remote document
        jQuery.ajax({
            url: url,
            type: type,
            dataType: "html",
            data: params,
            timeout: timeout,
            complete: function( res, status ) {
                // If successful, inject the HTML into all the matched elements
                if ( status === "success" || status === "notmodified" ) {
                    // See if a selector was specified
                    self.html( selector ?
                        // Create a dummy div to hold the results
                        jQuery("<div />")
                            // inject the contents of the document in, removing the scripts
                            // to avoid any 'Permission Denied' errors in IE
                            .append(res.responseText.replace(rscript, ""))
    
                            // Locate the specified elements
                            .find(selector) :
    
                        // If not, just inject the full result
                        res.responseText );
                }
    
                if ( callback ) {
                    self.each( callback, [res.responseText, status, res] );
                }
            }
        });
    
        return this;
    };
    

    不确定您是否有兴趣覆盖任何“标准”JQuery 函数,但这将允许您按照描述的方式使用 .load() 。

    【讨论】:

      【解决方案5】:

      我认为您无法从这里到达那里 - 正如@Pointy 所提到的,您需要访问 XmlHttpRequest 对象,以便您可以访问其上的 .abort() 方法。为此,您需要将对象返回给您的 .ajax() jQuery API。

      除非能够中止请求,否则要考虑的另一种方法是将超时的知识添加到回调函数中。你可以通过两种方式做到这一点 - 首先:

      var hasImage = false;
      
      $('#errorMessage')
          .idle(5000, function() {
      
              if(!hasImage) {
                  // 1. cancel .load()            
                  // 2. show error message
                  // 3. Add an aborted flag onto the element(s)
                  $('#myImage').data("aborted", true);
              }
          });
      

      还有你的回调:

      $('#myImage')
           .attr('src', '/url/anypath/image.png')
           .load(function(){
               if($(this).data("aborted")){
                   $(this).removeData("aborted");
                   return;
               }
               hasImage = true;
               // do something...
            });
      

      或者您可以绕过空闲来执行此特定功能:

      $('#myImage')
           .attr('src', '/url/anypath/image.png')
           .data("start", (new Date()).getTime())
           .load(function(){
               var start = $(this).data("start");
               $(this).removeData("start");
               if(((new Date()).getTime() - start) > 5000)
                   return;
      
               hasImage = true;
               // do something...
            });
      

      这两种方法都不理想,但我认为您不能直接取消从 jQuery 1.4 开始的加载 - 不过,这可能是对 jQuery 团队的一个不错的功能请求。

      【讨论】:

      • +1 但是.attr('src', '/url/anypath/image.png')在加载事件注册之前立即发出HTTP请求来获取图像。您应该将attr() 移到最后,在load() 之后。
      【解决方案6】:

      $('#myImage').load(function(){...})不是加载图片的函数调用,实际上是绑定回调到onload event的简写。

      因此,按照其他答案中的建议将timeout 参数添加到.load() method 将无效。

      它认为你的两个选择是:

      1. 继续你的路 跟随并做类似的事情 $('#myImage').attr('src', ''); 到 在它时间后取消图像加载 出去,或者

      2. 想办法用$.ajax( { ... , timeout: 5000, ...} );加载 图像而不是让 浏览器自动通过 &lt;img src="..."&gt; 属性。

      【讨论】:

        【解决方案7】:

        您可以在加载图像以及测试加载错误之前简单地设置一个超时时间。

        function LoadImage(yourImage) {
        
            var imageTimer = setTimeout(function () {
                //image could not be loaded:
                alert('image load timed out');
            }, 10000); //10 seconds
        
            $(yourImage).load(function (response, status, xhr) {
                if (imageTimer) {
        
                    if (status == 'error') {
                        //image could not be loaded:
                        alert('failed to load image');
        
                    } else {
                        //image was loaded:
                        clearTimeout(imageTimer);
                        //display your image...
                    }
        
                }
            });
        
        }
        

        【讨论】:

          猜你喜欢
          • 2014-03-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多