引言

JS的“加载”不能理解为下载,它是分为两个部分:下载,执行。默认的JS加载是同步的,因为浏览器需要一个稳定的DOM结构,而执行JS时可能会对DOM造成改变,所以在执行JS时一定会阻塞HTML的渲染。我们可以使用一些方法使JS的下载不会阻塞HTML渲染,但不能使JS的执行阻塞渲染。
 
以下从几个方面解释JS的加载:
 
  1、同步加载  
  2、异步加载
    2.1、Script DOM Element

    2.2、onload 时的异步加载

1、同步加载

同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止了后续的解析,因此停止了后续的文件加载(如图像)、渲染、代码执行。

使用方式如下:

<script src="http://domin1.com/script1.js"></script>

<script type="text/javascript">

  console.log('hello world');
</script>

这段代码中,如果请求的 script1.js 加载时间过长(domin1 被墙等原因),浏览器就会停止后续的文件下载,渲染,代码执行,第二个<script>中的"hello world"也无法显示。以前的处理方法是把<script>放置于页面末尾的</body>之前,可以使页面先显示出来,但这也只是另页面渲染不被阻塞而已,对于本例中第二个<script>的JS执行所造成的阻塞是无能为力的。

2、异步加载

异步加载又叫非阻塞,浏览器在下载 JS 同时,还会继续进行后续页面的处理,上述提到的第二个<script>的JS执行便不会被阻塞。

2.1、Script DOM Element 法

此方法不要求JS同源,使用方式如下:
(function (){
var async_script = document.createElement('script');
async_script.type = "text/javascript";
async_script.src = "http://domin.com/script.js";
var x = document.getElementsByTagName("script")[0];
x.ParentNode.insertBefore( async_script, x);
})();
以上代码使用 JS 创建了一个<script>插入到 document 中,便实现了异步加载JS。
将JS代码包裹在匿名函数中并立即执行的方式是为了保护变量名泄露到外部可见,比较常见。

但问题还是存在:这段代码在下载和执行完之前会阻止 onload 事件的触发,于是有了onload 时的异步加载。

2.2、onload 时的异步加载

(function() {
function async_load(){
var as = document.createElement("script");
as.type = "text/javascript";
as.src = "http://domain1.com/script.js";
var x = document.getElementsByTagName("script")[0];
x.parentNode.insertBefore(s, x);
}
if (window.attachEvent)
window.attachEvent('onload', async_load);
else
window.addEventListener('load', async_load, false);
})();
这段代码与之前区别在于它不是马上异步加载 JS ,而是在 onload 开始时才异步加载,便不会阻塞 onload 事件触发。

2.3、async 和 defer 属性

1. defer 属性
//async属性:
<script src="script1.js" async="async"></script> //defer属性:
<script src="script2.js" defer="defer"></script>

async属性使加载和渲染后续文档元素的过程将和当前js的加载与执行并行进行(异步);defer属性使下载后续文档元素的过程将和 script.js 的下载并行进行(异步),但是 script.js 的执行要在所有元素(DOM)解析完成之后,DOMContentLoaded 事件触发之前完成。但async属性是HTML5新增的,使用时需注意兼容性问题。

此处盗了个图:

该图中,绿线为HTML解析,蓝线为脚本下载,红线为脚本执行。我们可以看出默认情况下也就是同步模式下,脚本的下载和执行会阻塞HTML解析;异步模式中的async和defer两个属性在下载时均为异步不影响HTML解析,在执行均阻塞HTML解析,但defer胜在它可以控制脚本执行的时间,保证页面先加载出之后再执行脚本。

3、总述

除defer外,浏览器在下载完 JS 的内容后就会立即对其解析和执行,不管是同步加载还是异步加载。

文章中提到的异步加载,只能做到下载时的异步,但执行的时候依然会阻塞浏览器任何操作。
 
利用特殊的技巧可以做到 下载 与 执行的分离,下次再写了,天色太晚困的慌~。

JS的同步和异步加载的更多相关文章

  1. Angular.JS + Require.JS + angular-async-loader 来实现异步加载 angular 模块

    传统的 angular 应用不支持异步加载模块,必须在 module 启动的时候,所有模块必须预加载进来. 通过使用 angular-async-loader 库,我们可以使用 requirejs 等 ...

  2. JS文件延迟和异步加载:defer和async属性

    -般情况下,在文档的 <head> 标签中包含 JavaScript 脚本,或者导入的 JavaScript 文件.这意味着必须等到全部 JavaScript 代码都被加载.解析和执行完以 ...

  3. H5+JS+JQuery+ECharts实现异步加载

    这几天,看了一下ECharts官网的API和Demo发现很有意思,于是就利用模型预测产生的数据做一个伪实时的动态数据显示 . 首先,创建一个index.html的文件,我用的vscode打开的,进行编 ...

  4. Vue.js 子组件的异步加载及其生命周期控制

    前端开发社区的繁荣,造就了很多优秀的基于 MVVM 设计模式的框架,而组件化开发思想也越来越深入人心.这其中不得不提到 Vue.js 这个专注于 VM 层的框架. 本文主要对 Vue.js 组件化开发 ...

  5. jquery.datatable.js与CI整合 异步加载(大数据量处理)

    http://blog.csdn.net/kingsix7/article/details/38928685 1.CI 控制器添加方法 $this->show_fields_array=arra ...

  6. [转载]Javascript 同步异步加载详解

    http://handyxuefeng.blog.163.com/blog/static/4545217220131125022640/ 本文总结一下浏览器在 javascript 的加载方式. 关键 ...

  7. 关于requireJS的同步加载和异步加载

    这篇随笔主要记录require('name')和require(['name1','name2'])在同步和异步加载使用的区别 1.require('name')同步加载模块的形式 define(fu ...

  8. Javascript 异步加载详解(转)

    本文总结一下浏览器在 javascript 的加载方式. 关键词:异步加载(async loading),延迟加载(lazy loading),延迟执行(lazy execution),async 属 ...

  9. Javascript 异步加载详解

    Javascript 异步加载详解 本文总结一下浏览器在 javascript 的加载方式. 关键词:异步加载(async loading),延迟加载(lazy loading),延迟执行(lazy ...

随机推荐

  1. day23 内置函数,匿名函数,递归

    Python之路,Day11 = Python基础11 内置函数divmod(x, y)   # (商, 模)enumerate(可迭代对象)     # (序号,值)eval(字符串) # 把字符串 ...

  2. csp-s模拟测试87

    csp-s模拟测试87 考场状态还可以$T1$我当时以为我秒切,$T2$确认自己思路不对后毅然决然码上,$T3$暴力挂了太可惜了. 03:01:28 03:16:07 03:11:38 140 03: ...

  3. mysql重点,表查询操作和多表查询

    表单查询 1. 完整的查询语句语法 select distinct(* or 字段名 or 四则运算 )from 表名 where 条件 group by 条件 having 条件 order by ...

  4. 怎么规划一个零基础学习Unity3D的“方法”或者“流程”?

    具体出处:https://www.zhihu.com/question/35542990 我只是一个计算机相关专业毕业的,已经掌握了基础的C#并开发过.net的.目前突然心血来潮对unity3D有兴趣 ...

  5. 2019 CCPC 湖南全国邀请赛

    A. Chessboard 做法1 单纯形. 做法2 最大费用可行流问题,行列模型. 对每行建一个点,每列建一个点.物品 \(i\) 在 \((r,c)\),那么 \(r\) 向 \(c\) 连流量为 ...

  6. 如何在neo4j中创建新数据库?

    解决方案一: 由于使用Neo3.x创建新数据库而不删除现有数据库,所以只需在$NEO4J_HOME的conf的目录编辑neo4j.conf. 搜寻dbms.active_database=,其默认值应 ...

  7. tensorflow识别验证码(2)-tensorflow 编写CNN 识别验证码

    1. 导入依赖包 #coding:utf-8 from gen_captcha import gen_captcha_text_and_image from gen_captcha import nu ...

  8. 设置编辑工具UltraEdit的背景色为护眼颜色

    1.视图--->主题--->管理主题---> 2.--->编辑器--->纯文本--->第二个框(背景色) 3.--->规定自定义颜色--->建议(色调: ...

  9. loj6244 七选五

    题意:从n个数中选k个数,问有多少种排列与标准k项串恰好有x个位置相同. 标程: #include<cstdio> using namespace std; typedef long lo ...

  10. Ubuntu 18.04 Linux上安装Etherpad,基于Web的实时协作编辑器

    介绍 Etherpad是一个开源的,基于Web的实时协作编辑器(http://www.0834nanke.com) 它允许多个人使用他们的Web浏览器同时编辑文档. 它还提供了一些很酷的功能,如富文本 ...