Javascript 的同步加载和执行

现在的前端技术中,javascript(以下简称 js)异步加载的方案已经很多。在研究异步加载前,我们对同步加载了解的够多么?

同步加载大概意思为:浏览器解析文档的过程中,遇到加载 js 文件的代码,暂停文档解析,执行加载的代码,等待文件下载,等待文件中的代码执行完成,然后继续文档解析。

所以异步加载就是:浏览器解析文档过程中,遇到加载 js 文件的代码,暂停文档解析,执行加载代码,然后继续文档解析。不等待文件的下载。

同步加载的几种情况:

1、包含代码的 <script></script>  标签。虽然没有网络请求,但也可以当做是加载了文档内部的一段代码。标签内的代码按顺序执行,如果出现多个标签对,按标签对的出现顺序执行。

2、设置 src 属性的 <script></script>  标签。按标签的出现顺序执行。老的浏览器中,加载也是按顺序的:一个文件下载完成后,才开始下载下一个文件。较新的浏览器中(IE8+ 、FireFox3.5+ 、Chrome4+ 、Safari4+),为了减小请求时间以优化体验,下载可以是并行的,但是执行顺序还是按照标签出现的顺序。

3、在 <script></script>  标签中的代码,或者通过 src 引用的文件中,使用 document.write()  来写入的 js 代码。代码中也有上面 1 和 2 两种情况,执行顺序也是按照出现的先后。在 IE 中有个例外,在 <script></script>  标签中,假设有这种 document.write('<script src=""><\/script>')  加载文件的代码,则文件会放到 </script>  标签闭合处才执行。

同步加载的执行顺序:

因为核心 js 语言并不包含任何线程机制,并且浏览器端 js 也没增加任何线程机制,所以浏览器端 js 是单线程的(或者像单线程一样工作)。因此 js 代码只能按顺序执行,就算浏览器为了体验可以并行下载多个 js 文件,但就算个别文件下载的特别快,也得按顺序被执行。

同步加载的应用:

1、我们平时的开发中用的基本上都是同步加载。比如先加载一个 jQuery 库文件,接下来就可以使用 $ 符号了。原理上,是因为 js 代码的运行环境是在一个全局对象里,代码声明全局变量和函数,实际是在修改全局对象的属性,这些修改会被保持着,所以下一段代码可以使用上一段代码声明的全局变量和函数。

2、常用于跨域请求数据的 JSONP。我们在本站声明一个回调函数,然后向外站请求一个 js 文件,文件中的代码是用外站的数据对本站函数进行调用,就实现了使用外站数据的目的。虽然函数是本站声明的,数据是外站的,外站调用本站函数,但是把它理解为同步加载和执行就简单了。

3、前端优化中的 “脚本尽量放在页面底部” 这条规则,也很好解释。因为是同步加载和执行,js 的加载和执行都会阻塞页面的解析,如果时间长了,体验很不好,所以将脚本尽量放在底部,影响最小。

几个容易混淆的问题:

1、将 document.write('<script src=""><\/script>')  这类代码,移到 window.onload  事件中,算异步加载么?

还是同步加载。这样改其实是改变了这段加载代码的执行时机,推迟到文件加载完成时才执行,但并没有改变加载的方式。

2、同步加载第 3 中情况中,如果嵌套了很多层,执行顺序是怎样的?比如,在被加载的 js 文件中,又用 document.write()  来加载了一个 js 文件。

还是按出现顺序来执行。根据单线程的模型,只能逐个解析和执行。

 

最后站在浏览器的角度总结下:因为浏览器的 js 是单线程的,而且 js 都运行在 window 这个全局对象中,所以必须逐个解析、加载和执行 <script></script>  标签中包含的代码或文件;为了保证这种顺序,需要同步加载 js 文件。

在 GitHub 上放了点测试代码。

 

参考资料:

Coupling asynchronous scripts
Browser script loading roundup
Positioning Inline Scripts
Javascript 文件的同步加载与异步加载
JavaScript中的对象动态加载技术
Javascript在页面加载时的执行顺序

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">