Javascript - Como detectar se o documento foi carregado (IE 7 / Firefox 3)

163

Quero chamar uma função após o carregamento de um documento, mas o documento pode ou não ter terminado o carregamento ainda. Se ele carregou, posso chamar a função Se NÃO foi carregado, posso anexar um ouvinte de evento. Não consigo adicionar um listener de eventos depois que o onload já foi acionado, pois não será chamado. Então, como posso verificar se o documento foi carregado? Eu tentei o código abaixo, mas ele não funciona totalmente. Alguma ideia?

var body = document.getElementsByTagName('BODY')[0];
// CONDITION DOES NOT WORK
if (body && body.readyState == 'loaded') {
    DoStuffFunction();
} else {
    // CODE BELOW WORKS
    if (window.addEventListener) {  
        window.addEventListener('load', DoStuffFunction, false);
    } else {
        window.attachEvent('onload', DoStuffFunction);
    }
}
Marcos
fonte
5
"Quero chamar uma função após o carregamento de um documento, mas o documento pode ou não ter terminado o carregamento ainda." Isso não computa.
Richard Simões
7
Eu acredito que ele quer dizer que ele não tem controle sobre quando seu bloco de código é executado inicialmente, mas deseja garantir que DoStuffFunction () não seja chamado antes que o documento termine de carregar.
11119 Ben Blank

Respostas:

257

Não há necessidade de todo o código mencionado pelos galambalazs. A maneira entre navegadores de fazê-lo em JavaScript puro é simplesmente testar document.readyState:

if (document.readyState === "complete") { init(); }

É também assim que o jQuery faz isso.

Dependendo de onde o JavaScript está carregado, isso pode ser feito dentro de um intervalo:

var readyStateCheckInterval = setInterval(function() {
    if (document.readyState === "complete") {
        clearInterval(readyStateCheckInterval);
        init();
    }
}, 10);

De fato, document.readyStatepode ter três estados:

Retorna "carregamento" enquanto o documento está sendo carregado, "interativo" quando terminar de analisar, mas ainda carrega sub-recursos, e "concluído" após o carregamento. - document.readyState na Mozilla Developer Network

Portanto, se você só precisa que o DOM esteja pronto, verifique document.readyState === "interactive". Se você precisar que a página inteira esteja pronta, incluindo imagens, verifique document.readyState === "complete".

Laurent
fonte
3
@costa, se document.readyState == "complete"isso significa que tudo, incluindo imagens, foi carregado.
precisa
Estou usando a combinação dos dois eventos e document.readyStatepara garantir que a função seja iniciada após o DOM ser analisado ou mais tarde, dependendo de quando foi chamado. Existe um evento para interatividade readyState ?
Tomáš Zato - Restabelece Monica
3
Eu usaria /loaded|complete/.test(document.readyState). Alguns navegadores configurados document.readyStatepara "carregado" em vez de "completo". Além disso, document.readyState NÃO garante que as fontes tenham sido carregadas, não há uma maneira realmente boa de testar isso sem um plug-in.
Ryan Taylor
2
Que tal document.onreadystatechange? Isso parece mais otimizado se os navegadores suportarem. stackoverflow.com/questions/807878/…
2
Eu acho que seria melhor procurar document.readyState !== "loading", para o estado "DOM ready". Isso evita que surjam problemas se a readyStateverificação for atrasada por algum motivo (após o estado "interativo").
Rnevius 21/09/2015
32

Não há necessidade de uma biblioteca. O jQuery usou esse script por um tempo, btw.

http://dean.edwards.name/weblog/2006/06/again/

// Dean Edwards/Matthias Miller/John Resig

function init() {
  // quit if this function has already been called
  if (arguments.callee.done) return;

  // flag this function so we don't do the same thing twice
  arguments.callee.done = true;

  // kill the timer
  if (_timer) clearInterval(_timer);

  // do stuff
};

/* for Mozilla/Opera9 */
if (document.addEventListener) {
  document.addEventListener("DOMContentLoaded", init, false);
}

/* for Internet Explorer */
/*@cc_on @*/
/*@if (@_win32)
  document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
  var script = document.getElementById("__ie_onload");
  script.onreadystatechange = function() {
    if (this.readyState == "complete") {
      init(); // call the onload handler
    }
  };
/*@end @*/

/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
  var _timer = setInterval(function() {
    if (/loaded|complete/.test(document.readyState)) {
      init(); // call the onload handler
    }
  }, 10);
}

/* for other browsers */
window.onload = init;
gblazex
fonte
1
Exatamente o que eu estava procurando - a função jQuery.ready sem a biblioteca jQuery. Thanx!
stricjux
3
Perdeu totalmente o objetivo da pergunta. initnão será executado se esse código que você postou for incluído após o carregamento da página, que é o ponto do OP: ele / ela não pode controlar quando o script está incluído. (note que apenas o setIntervalramo vai funcionar)
Roatin Marth
3
Isso pertence a uma biblioteca. Juntamente com todas as outras rodas, as pessoas normalmente reinventam.
b01 13/05
14

Você provavelmente deseja usar algo como jQuery, que facilita a programação JS.

Algo como:

$(document).ready(function(){
   // Your code here
});

Parece fazer o que você procura.

dan
fonte
2
E se ele quer ver como jQuery faz isso de uma maneira portátil, fonte do jQuery está lá para a inspeção :-)
Thomas L Holaday
7
E, caso não esteja claro, se ready()for chamado após o carregamento do documento, a função transmitida será executada imediatamente.
11459 Ben Blank
2
@ Ben Blank: a não ser, é claro, que o próprio jQuery seja incluído após o carregamento do documento;)
Roatin Marth
@ Roatin Marth - Na verdade, isso funciona bem também. (Apenas tentei com o jQuery 1.7.1 no FF8 e no IE8.) #
5045 Ben Blank
35
-1: mesmo que a resposta faça sentido, o OP nunca mencionou o jQuery. Usar todo o projeto jQuery apenas para preparar o documento é um exagero.
marcgg
8
if(document.readyState === 'complete') {
    DoStuffFunction();
} else {
    if (window.addEventListener) {  
        window.addEventListener('load', DoStuffFunction, false);
    } else {
        window.attachEvent('onload', DoStuffFunction);
    }
}
Jman
fonte
Não parece trabalho na última Chrome document.loadedé sempre indefinido
Aniket
isso foi em 2010 :). Agora vou usarbody.readyState === 'loaded'
Jman
6

Se você realmente deseja que esse código seja executado no carregamento , não no dom já (ou seja, você também precisa que as imagens sejam carregadas), infelizmente a função ready não faz isso por você. Eu geralmente apenas faço algo assim:

Inclua no documento javascript (ou seja, sempre chamado antes do carregamento do onload):

var pageisloaded=0;
window.addEvent('load',function(){
 pageisloaded=1;
});

Então seu código:

if (pageisloaded) {
 DoStuffFunction();
} else {
 window.addEvent('load',DoStuffFunction);
}

(Ou o equivalente em sua estrutura de preferência.) Eu uso esse código para fazer o precaching de javascript e imagens para páginas futuras. Como o material que estou recebendo não é usado para esta página, não quero que ela tenha precedência sobre o rápido download de imagens.

Pode haver uma maneira melhor, mas ainda não a encontrei.

Nathan Stretch
fonte
4

O Mozila Firefox diz que onreadystatechangeé uma alternativa ao DOMContentLoaded.

// alternative to DOMContentLoaded
document.onreadystatechange = function () {
    if (document.readyState == "complete") {
        initApplication();
    }
}

No DOMContentLoadeddocumento do Mozila diz:

O evento DOMContentLoaded é acionado quando o documento foi completamente carregado e analisado, sem aguardar que folhas de estilo, imagens e sub-quadros terminem de carregar (o evento load pode ser usado para detectar uma página totalmente carregada).

Acho que o loadevento deve ser usado para um carregamento completo de documentos + recursos.

Mostafa Talebi
fonte
3

O exemplo acima com o JQuery é a maneira mais fácil e mais usada. No entanto, você pode usar javascript puro, mas tente definir esse script na cabeça para que seja lido no início. O que você está procurando éwindow.onload evento.

Abaixo está um script simples que eu criei para executar um contador. O contador então pára após 10 iterações

window.onload=function()
{
    var counter = 0;
    var interval1 = setInterval(function()
    { 
        document.getElementById("div1").textContent=counter;
        counter++; 
        if(counter==10)
        {
            clearInterval(interval1);
        }
    },1000);

}
Talha
fonte
2

Tente o seguinte:

var body = document.getElementsByTagName('BODY')[0];
// CONDITION DOES NOT WORK
if ((body && body.readyState == 'loaded') || (body &&  body.readyState == 'complete') ) {
    DoStuffFunction();
} else {
    // CODE BELOW WORKS
    if (window.addEventListener) {
        window.addEventListener('load', DoStuffFunction, false);
    } else {
        window.attachEvent('onload',DoStuffFunction);
    }
}
ferir
fonte
1

Eu tenho outra solução, meu aplicativo precisa ser iniciado quando um novo objeto do MyApp é criado, portanto, parece:

function MyApp(objId){
     this.init=function(){
        //.........
     }
     this.run=function(){
          if(!document || !document.body || !window[objId]){
              window.setTimeout(objId+".run();",100);
              return;
          }
          this.init();
     };
     this.run();
}
//and i am starting it 
var app=new MyApp('app');

está funcionando em todos os navegadores, que eu sei.

vitus
fonte