2015-09-18 19 views
5

Proszę zobaczyć kod:DOMContentLoaded bloki strona ładowanie

<!-- ... --> 
<head> 
    <style type="text/css"> body { background: gray; } </style> 
</head> 
<body> 
    <p> 
     Firefox does not even shows blank page. 
     Tab is stuck in "suggested sites" for 5 seconds. 
    </p> 
    <p> 
     Chrome show just blank white. No text, no background. For 5 seconds. 
    </p> 
    <p> 
     DOMContentLoaded event handler blocks page 
     loading and rendering. Browser does not start 
     rendering page until DOMContentLoaded 
     handler function return. 
    </p> 

    <script> 
     document.addEventListener('DOMContentLoaded', function() { 
      var timestamp = Date.now() + 5000; while (Date.now() < timestamp); 
      // or synchronous 5 seconds XHR as an equivalent of loop 
     }); 
    </script> 
</body> 
<!-- ... --> 

statyczny html + css jest więcej niż wystarczający do renderowania zawartości (choć bez IMG i korzystny układ bloków, ale nie zależy na imgs rozmiarach). Ogólny układ strony powinien być wyświetlany natychmiast, tak jak zawsze był przeznaczony. I dopiero po renderowaniu (lub przynajmniej zaczynaniu go rysować) Javsacript powinien działać, nieważne czy to po prostu kontroluje wiązania kliknięć czy nieskończoną pętlę jak w przykładzie tutaj.

Jak mogę uruchomić JS po tym, jak układ strony statycznej zostanie faktycznie renderowany, a przynajmniej zacznie się wyświetlać?

(i „gotowe” zdarzenie nie jest tu odpowiednie, ponieważ nie jest gwarantowana na ogień w każdym rozsądnym czasie)

  • Jak widać z przykładu nie używam zapisu dokumentu ani planują.
  • Umieszczam też skrypt tuż przed tagiem zamykającym body
  • Nie wykonuję żadnej prawdziwej pracy w tagu skryptu - podoba mi się wydarzenie.

Dlaczego przeglądarka uniemożliwia (blokuje) użytkownika oglądanie statycznie zdefiniowanej treści? Czy co najmniej nowoczesne przeglądarki mogą zatrzymać te bzdury?

UPD. wyjaśnienie

Jeśli używasz DOMContentLoaded na regularne zadania pozornie nieszkodliwe (otrzymywaniem ofert przyciski wydarzeń, inicjowanie obciążenia asynchronicznej z innym kodem, etc.), które w rzeczywistości NIE opóźniając użytkownikowi treści widząc i to jest prawdziwy problem z DOMContentLoaded. Blokowanie pętli jest tutaj celowe, tylko po to, aby udowodnić, że naprawdę blokuje, dla tych, którzy błędnie wierzą, że DOMContentLoaded jest "asynchroniczną"/"nieblokującą" bezpieczną rzeczą (która nie jest).

+1

[Dlaczego nie używać 'setTimeout'?] (Http://jsfiddle.net/ods26xk1/1) To nie jest do końca jasne, co starasz się osiągnąć tutaj. –

+0

@ AndréDion Tak, nie do końca jasne, ale stwierdziłem, że blokowanie było zamierzone - chciał tylko, aby zaczął się po wyświetleniu głównej zawartości. – wwwmarty

+0

może być while() jest skrótem do synchronicznego wywołania ajax ... – wwwmarty

Odpowiedz

2

Ciekawe i nieoczekiwane. Rozwiązałem go requestAnimationFrame (callback), tak jak poniżej:

function foo() { 
    window.requestAnimationFrame(function() { 
     window.requestAnimationFrame(function() { 
      var timestamp = Date.now() + 5000; while (Date.now() < timestamp){}; 
      alert('now'); 
     }); 
    }); 
} 
document.addEventListener('DOMContentLoaded', foo); 
+0

Wspaniałe znalezisko, dziękuję. Dokładnie to, jak się spodziewałem, działa. To dziwne, że nie ma innego wygodnego i standardowego sposobu na taką podstawową rzecz, a problem jest ignorowany. –

+1

I jak na ironię działa w FF, ale nie w Chrome :) –

+0

Ok, to bardzo denerwujące. Chrome lubi drugą animację, ale nie pierwszą. Zaktualizowana odpowiedź .... i jestem przerażony, aby spróbować tego w IE;) – wwwmarty