JavaScript - jak wykryć, czy dokument został załadowany (IE 7 / Firefox 3)

163

Chcę wywołać funkcję po załadowaniu dokumentu, ale załadowanie dokumentu mogło się jeszcze skończyć lub nie. Jeśli się załadował, mogę po prostu wywołać funkcję. Jeśli się NIE załadował, mogę dołączyć detektor zdarzeń. Nie mogę dodać detektora zdarzeń, gdy onload został już uruchomiony, ponieważ nie zostanie wywołany. Jak więc mogę sprawdzić, czy dokument się załadował? Wypróbowałem poniższy kod, ale nie do końca działa. Jakieś pomysły?

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
źródło
5
„Chcę wywołać funkcję po załadowaniu dokumentu, ale ładowanie dokumentu mogło się jeszcze nie zakończyć”. To się nie liczy.
Richard Simões
7
Uważam, że ma na myśli, że nie ma kontroli nad początkowym uruchomieniem jego bloku kodu, ale chce się upewnić, że funkcja DoStuffFunction () nie zostanie wywołana przed zakończeniem ładowania dokumentu.
Ben Blank,

Odpowiedzi:

257

Nie ma potrzeby, aby cały kod wspomniany przez galambalazs. Aby to zrobić w czystym JavaScript, wystarczy przetestować document.readyState:

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

Tak też robi to jQuery.

W zależności od tego, gdzie ładowany jest JavaScript, można to zrobić w przedziale:

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

W rzeczywistości document.readyStatemoże mieć trzy stany:

Zwraca „ładowanie” podczas wczytywania dokumentu, „interaktywne” po zakończeniu analizowania, ale nadal ładuje zasoby podrzędne, oraz „zakończone” po załadowaniu. - document.readyState w Mozilla Developer Network

Więc jeśli potrzebujesz tylko DOM, aby był gotowy, sprawdź document.readyState === "interactive". Jeśli chcesz, aby cała strona była gotowa, w tym obrazy, sprawdź document.readyState === "complete".

laurent
źródło
3
@costa, jeśli document.readyState == "complete"to znaczy, że wszystko, łącznie z obrazami, zostało załadowane.
laurent
Używam kombinacji obu zdarzeń i document.readyStateaby upewnić się, że funkcja uruchomi się po przeanalizowaniu DOM lub później, w zależności od tego, kiedy została wywołana. Czy jest impreza interaktywna readyState ?
Tomáš Zato - Przywróć Monikę
3
Użyłbym /loaded|complete/.test(document.readyState). Niektóre przeglądarki są ustawione document.readyStatejako „załadowane” zamiast „zakończone”. Ponadto document.readyState NIE gwarantuje, że czcionki zostały załadowane, nie ma naprawdę dobrego sposobu na przetestowanie tego bez wtyczki.
Ryan Taylor
2
O co chodzi document.onreadystatechange? Wydaje się to bardziej uproszczone, jeśli obsługują to przeglądarki. stackoverflow.com/questions/807878/…
2
Myślę, że lepiej byłoby sprawdzić document.readyState !== "loading"stan „DOM gotowy”. Zapobiega to pojawianiu się problemów, jeśli z readyStatejakiegoś powodu zostanie sprawdzone z opóźnieniem (po stanie „interaktywnym”).
rnevius
32

Nie ma potrzeby posiadania biblioteki. Przy okazji, jQuery używał tego skryptu przez jakiś czas.

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
źródło
1
Dokładnie to, czego szukałem - funkcja jQuery.ready bez biblioteki jQuery. Dzięki!
stricjux
3
Całkowicie nie trafiłem w sedno pytania. initnie będzie działać, jeśli ten kod, który wysłałeś, zostanie uwzględniony po załadowaniu strony, co jest celem OP: nie może kontrolować, kiedy jego skrypt jest dołączony. (pamiętaj, że tylko setIntervaloddział będzie działał)
Roatin Marth
3
To należy do biblioteki. Wraz ze wszystkimi innymi kołami ludzie często odkrywają na nowo.
b01
14

Prawdopodobnie chcesz użyć czegoś takiego jak jQuery, co ułatwia programowanie w JS.

Coś jak:

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

Wydaje się, że zrobi to, czego szukasz.

dan
źródło
2
A jeśli chce zobaczyć, jak jQuery robi to w przenośny sposób, źródło jQuery jest tam do wglądu :-)
Thomas L Holaday
7
A jeśli nie jest jasne, jeśli ready()zostanie wywołana po załadowaniu dokumentu, przekazana funkcja jest uruchamiana natychmiast.
Ben Blank
2
@Ben Blank: o ile oczywiście samo jQuery nie jest dołączone po załadowaniu dokumentu;)
Roatin Marth
@Roatin Marth - Właściwie to też działa dobrze. (Właśnie wypróbowałem to z jQuery 1.7.1 na FF8 i IE8.)
Ben Blank,
35
-1: nawet jeśli odpowiedź ma sens, OP nigdy nie wspomniał o jQuery. Używanie całego projektu jQuery tylko do przygotowania dokumentu jest zbyteczne.
marcgg
8
if(document.readyState === 'complete') {
    DoStuffFunction();
} else {
    if (window.addEventListener) {  
        window.addEventListener('load', DoStuffFunction, false);
    } else {
        window.attachEvent('onload', DoStuffFunction);
    }
}
Jman
źródło
Wygląda na to, że nie działa w najnowszym Chrome document.loadedjest zawsze niezdefiniowany
Aniket
to był 2010 rok :). Teraz body.readyState === 'loaded'
użyję
6

Jeśli faktycznie chcesz, aby ten kod działał przy ładowaniu , a nie w domready (tj. Potrzebujesz również ładować obrazy), to niestety funkcja ready nie robi tego za Ciebie. Generalnie robię coś takiego:

Uwzględnij w javascript w dokumencie (tj. Zawsze wywoływane przed uruchomieniem onload):

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

Następnie twój kod:

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

(Lub odpowiednik w ramach twoich preferencji.) Używam tego kodu do przygotowania kodu JavaScript i obrazów dla przyszłych stron. Ponieważ to, co otrzymuję, nie jest w ogóle używane na tej stronie, nie chcę, aby miało pierwszeństwo przed szybkim pobieraniem obrazów.

Może jest lepszy sposób, ale jeszcze go nie znalazłem.

Nathan Stretch
źródło
4

Mozila Firefox twierdzi, że onreadystatechangejest to alternatywa dla DOMContentLoaded.

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

W DOMContentLoadeddokumencie Mozili mówi:

Zdarzenie DOMContentLoaded jest wywoływane po całkowitym załadowaniu i przeanalizowaniu dokumentu, bez czekania na zakończenie ładowania arkuszy stylów, obrazów i ramek podrzędnych (zdarzenie load może służyć do wykrywania w pełni załadowanej strony).

Myślę, że loadwydarzenie powinno być używane do pełnego załadowania dokumentu + zasobów.

Mostafa Talebi
źródło
3

Powyższy z JQuery jest najłatwiejszym i najczęściej używanym sposobem. Możesz jednak użyć czystego javascript, ale spróbuj zdefiniować ten skrypt w głowie, aby był czytany na początku. To, czego szukasz, to window.onloadwydarzenie.

Poniżej znajduje się prosty skrypt, który utworzyłem, aby uruchomić licznik. Następnie licznik zatrzymuje się po 10 iteracjach

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

}
Talha
źródło
2

Spróbuj tego:

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);
    }
}
smit
źródło
1

Mam inne rozwiązanie, moją aplikację trzeba uruchomić przy tworzeniu nowego obiektu MyApp, więc wygląda to tak:

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

działa na wszystkich przeglądarkach, które znam.

vitus
źródło