Pergunta

Eu gostaria de cancelar uma operação .load (), quando o carregamento () não retornar em 5 segundos. Se for, então eu mostro uma mensagem de erro como 'desculpe, nenhuma imagem carregada'.

O que eu tenho é ...

... o manuseio de tempo limite:

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

... inicializando o tempo limite da mensagem de erro:

var hasImage = false;

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

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

... o carregamento da imagem:

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

A única coisa que eu não consegui descobrir é como cancelar a carga em execução () (se possível).

Editar:

Outra maneira: como evito o método .load () para chamar sua função de retorno de chamada quando está retornando?

Foi útil?

Solução

Se você deseja qualquer manuseio personalizado como esse, simplesmente não pode usar a função jQuery.load (). Você terá que atualizar para o jQuery.ajax (), que eu recomendo de qualquer maneira, pois você pode fazer muito mais com ele, especialmente se precisar de algum tipo de manuseio de erros, será necessário.

Use a opção Beforesend para jQuery.ajax e capture o XHR. Em seguida, você pode criar retorno de chamada que pode cancelar o XHR após o tempo limite e os retornos de chamada, conforme necessário.

Este código não é testado, mas deve começar.

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
    ...
  }
});

Outras dicas

Sua pergunta secundária reformulada:
Como cancelar as funções pendentes de retorno de chamada, criadas usando o método .load ()?

Você pode cancelar todos os retornos de chamada do jQuery, usando esta opção 'nuclear':

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

Eu acho que a coisa mais simples a fazer seria usar $.ajax diretamente. Dessa forma, você pode iniciar um tempo limite e, a partir do tempo limite, definir um sinalizador que o manipulador na chamada do Ajax pode verificar. O tempo limite também pode mostrar uma mensagem ou qualquer outra coisa.

Se você carregar este código após o carregamento do jQuery, poderá ligar para .load () com um parâmetro de tempo limite.

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;
};

Não tenho certeza se você está interessado em substituir quaisquer funções jQuery "padrão", mas isso permitiria que você use .load () da maneira que você descreveu.

Eu não acho que você pode chegar lá daqui - como @Pointy mencionado, você precisa chegar ao objeto xmlhttprequest para que você possa acessar o .abort() método nele. Para isso, você precisa do .ajax() API jQuery que retorna o objeto para você.

Exceto a capacidade de abortar a solicitação, outro método a considerar é adicionar conhecimento do tempo limite à função de retorno de chamada. Você pode fazer isso de duas maneiras - primeiro:

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);
        }
    });

E seu retorno de chamada:

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

Ou você pode ignorar o ocioso para esta funcionalidade específica:

$('#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...
      });

Nenhuma das abordagens é ideal, mas acho que você não pode cancelar diretamente a carga do JQuery 1.4 - pode ser uma boa solicitação de recurso para a equipe jQuery.

$('#myImage').load(function(){...}) não é uma chamada de função para carregar a imagem, na verdade é abreviada para ligar um retorno de chamada ao onload evento.

Portanto, adicionando um timeout parâmetro para o .load() método Conforme sugerido em outras respostas, não terá efeito.

Acho que suas duas opções são:

  1. Continue no caminho que você está seguindo e faça algo como$('#myImage').attr('src', ''); para cancelar a carga da imagem após a hora de sair, ou

  2. Encontre uma maneira de usar $.ajax( { ... , timeout: 5000, ...} ); para carregar a imagem em vez de deixar o navegador fazer isso automaticamente através do<img src="..."> atributo.

Você pode simplesmente definir um tempo limite antes de carregar a imagem e testar um erro de carga.

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...
            }

        }
    });

}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top