我做过一些基于web的项目,但我没有过多考虑一个普通网页的加载和执行顺序。但现在我需要知道细节。很难从谷歌或SO中找到答案,所以我创造了这个问题。

一个示例页面是这样的:

<html>
 <head>
  <script src="jquery.js" type="text/javascript"></script>
  <script src="abc.js" type="text/javascript">
  </script>
  <link rel="stylesheets" type="text/css" href="abc.css"></link>
  <style>h2{font-wight:bold;}</style>
  <script>
  $(document).ready(function(){
     $("#img").attr("src", "kkk.png");
  });
 </script>
 </head>
 <body>
    <img id="img" src="abc.jpg" style="width:400px;height:300px;"/>
    <script src="kkk.js" type="text/javascript"></script>
 </body>
</html>

下面是我的问题:

这个页面是如何加载的? 装载的顺序是什么? JS代码什么时候执行?(内联和外部) CSS什么时候执行(应用)? 什么时候$(document)。准备好被处决了吗? 会下载abc.jpg吗?还是直接下载kkk.png?

我有以下认识:

浏览器首先加载html (DOM)。 浏览器开始逐行从上到下加载外部资源。 如果遇到<script>,加载将被阻塞,等待JS文件加载并执行,然后继续。 其他资源(CSS/图像)并行加载并在需要时执行(如CSS)。

或者是这样的:

浏览器解析html (DOM)并以数组或类似堆栈的结构获取外部资源。html加载后,浏览器开始并行加载结构中的外部资源并执行,直到所有资源都加载完毕。然后DOM将根据用户的行为(取决于JS)进行相应的更改。

有人能详细解释一下当你得到一个html页面的响应时发生了什么吗?这在不同的浏览器中是否有所不同?有关于这个问题的参考资料吗?

谢谢。

编辑:

我用Firebug在Firefox中做了一个实验。如下图所示:


当前回答

Dynatrace AJAX Edition向您展示了页面加载、解析和执行的确切顺序。

其他回答

编辑:现在是2022年。如果你对网页的加载和执行以及浏览器如何工作的详细报道感兴趣,你应该查看https://browser.engineering/(在https://github.com/browserengineering/book上开源)


根据你们的样品,

<html>
 <head>
  <script src="jquery.js" type="text/javascript"></script>
  <script src="abc.js" type="text/javascript">
  </script>
  <link rel="stylesheets" type="text/css" href="abc.css"></link>
  <style>h2{font-wight:bold;}</style>
  <script>
  $(document).ready(function(){
     $("#img").attr("src", "kkk.png");
  });
 </script>
 </head>
 <body>
    <img id="img" src="abc.jpg" style="width:400px;height:300px;"/>
    <script src="kkk.js" type="text/javascript"></script>
 </body>
</html>

执行流程大致如下:

The HTML document gets downloaded The parsing of the HTML document starts HTML Parsing reaches <script src="jquery.js" ... jquery.js is downloaded and parsed HTML parsing reaches <script src="abc.js" ... abc.js is downloaded, parsed and run HTML parsing reaches <link href="abc.css" ... abc.css is downloaded and parsed HTML parsing reaches <style>...</style> Internal CSS rules are parsed and defined HTML parsing reaches <script>...</script> Internal Javascript is parsed and run HTML Parsing reaches <img src="abc.jpg" ... abc.jpg is downloaded and displayed HTML Parsing reaches <script src="kkk.js" ... kkk.js is downloaded, parsed and run Parsing of HTML document ends

请注意,由于浏览器的行为,下载可能是异步的和非阻塞的。例如,在Firefox中有这样的设置,它限制每个域同时请求的数量。

另外,根据组件是否已经缓存,在不久的将来可能不会再次请求该组件。如果组件已经被缓存,组件将从缓存中加载,而不是实际的URL。

当解析结束,文档准备就绪并加载时,将触发onload事件。因此,当onload被触发时,$("#img").attr("src","kkk.png");运行。所以:

文档准备就绪,onload启动。 Javascript执行$("#img")。attr(“src”、“kkk.png”); Kkk.png下载并加载到#img中

$(document).ready()事件实际上是在加载所有页面组件并准备就绪时触发的事件。阅读更多信息:http://docs.jquery.com/Tutorials:Introducing_$(document).ready()

编辑-这部分详细阐述了“是否平行”部分:

默认情况下,根据我目前的理解,浏览器通常以3种方式运行每个页面:HTML解析器、Javascript/DOM和CSS。

HTML解析器负责解析和解释标记语言,因此必须能够调用其他两个组件。

例如,当解析器遇到这一行时:

<a href="#" onclick="alert('test');return false;" style="font-weight:bold">a hypertext link</a>

解析器将进行3次调用,两次调用Javascript,一次调用CSS。首先,解析器将创建这个元素并在DOM名称空间中注册它,以及与该元素相关的所有属性。其次,解析器将调用onclick事件绑定到这个特定的元素。最后,它将再次调用CSS线程,将CSS样式应用于这个特定的元素。

执行是自上而下和单线程的。Javascript看起来是多线程的,但实际上它是单线程的。这就是为什么当加载外部javascript文件时,主HTML页面的解析被挂起。

然而,CSS文件可以同时下载,因为CSS规则总是被应用-这意味着元素总是用定义的最新CSS规则重新绘制-从而使它不阻塞。

一个元素只有在被解析后才在DOM中可用。因此,在处理特定元素时,脚本总是放置在window onload事件之后或其中。

这样的脚本会导致错误(在jQuery上):

<script type="text/javascript">/* <![CDATA[ */
  alert($("#mydiv").html());
/* ]]> */</script>
<div id="mydiv">Hello World</div>

因为在解析脚本时,#mydiv元素仍然没有定义。相反,这是可行的:

<div id="mydiv">Hello World</div>
<script type="text/javascript">/* <![CDATA[ */
  alert($("#mydiv").html());
/* ]]> */</script>

OR

<script type="text/javascript">/* <![CDATA[ */
  $(window).ready(function(){
                    alert($("#mydiv").html());
                  });
/* ]]> */</script>
<div id="mydiv">Hello World</div>

AFAIK,浏览器(至少Firefox)在解析每个资源时立即请求它。如果它遇到一个img标记,它将在img标记解析完成后立即请求该图像。这甚至可以在它接收到HTML文档的全部之前……也就是说,当这种情况发生时,它可能还在下载HTML文档。

对于Firefox,有一些浏览器队列可以应用,这取决于它们在about:config中的设置方式。例如,它不会尝试一次从同一服务器下载超过8个文件…额外的请求将被排队。我认为有每个域的限制,每个代理的限制,以及其他东西,这些都在Mozilla网站上有文档,可以在about:config中设置。我在某处读到IE没有这样的限制。

jQuery ready事件在主HTML文档下载完成并对其进行DOM解析后立即触发。然后,一旦所有链接的资源(CSS、图像等)都下载并解析完毕,load事件就会触发。这在jQuery文档中有明确说明。

如果您想控制所有加载的顺序,我相信最可靠的方法是通过JavaScript。

如果你问这个问题是因为你想要加快你的网站速度,请查看雅虎网站的最佳实践。它有很多加速你的网站的最佳实践。

The chosen answer looks like does not apply to modern browsers, at least on Firefox 52. What I observed is that the requests of loading resources like css, javascript are issued before HTML parser reaches the element, for example <html> <head> <!-- prints the date before parsing and blocks HTMP parsering --> <script> console.log("start: " + (new Date()).toISOString()); for(var i=0; i<1000000000; i++) {}; </script> <script src="jquery.js" type="text/javascript"></script> <script src="abc.js" type="text/javascript"></script> <link rel="stylesheets" type="text/css" href="abc.css"></link> <style>h2{font-wight:bold;}</style> <script> $(document).ready(function(){ $("#img").attr("src", "kkk.png"); }); </script> </head> <body> <img id="img" src="abc.jpg" style="width:400px;height:300px;"/> <script src="kkk.js" type="text/javascript"></script> </body> </html> What I found that the start time of requests to load css and javascript resources were not being blocked. Looks like Firefox has a HTML scan, and identify key resources(img resource is not included) before starting to parse the HTML.

Dynatrace AJAX Edition向您展示了页面加载、解析和执行的确切顺序。