引言

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. js代码触发事件

    /*** * 需要触发谁的点击事件 * @param how_id 节点的id 如:<input id='test'/> 则how_id=test * @param how_this 这个 ...

  2. kubernetes istio的快速安装和使用例子

    安装 [root@master ~]# wget https://github.com/istio/istio/releases/download/1.1.5/istio-1.1.5-linux.ta ...

  3. C++利用动态数组实现顺序表(不限数据类型)

    通过类模板实现顺序表时,若进行比较和遍历操作,模板元素可以通过STL中的equal_to仿函数实现,或者通过回调函数实现.若进行复制操作,可以采用STL的算法函数,也可以通过操作地址实现.关于回调函数 ...

  4. 如何查找一个命令由哪个rpm安装&&rpm 的相关查询方法

    [root@test-can-nginx src]# which python3 /usr/bin/python3 [root@test-can-nginx src]# rpm -qf /usr/bi ...

  5. SpringAOP中的aop:config标签

    我们使用Spring的AOP功能的时候发现,我们使用普通的配置方式的时候,我们无法精确的确定将切面类中的哪个方法切入到哪个切入点上, 所以我们可以使用aop的专用标签来完成相关的配置.其中主要表现是使 ...

  6. 20.multi_case05

    #coding:utf-8 # 通过gather方法 import asyncio async def a(t): print('-->', t) await asyncio.sleep(0.5 ...

  7. Web-动态页面

    <!doctype html>01 - JavaEE- JSP - EL&JSTL figure:first-child { margin-top: -20px; } #write ...

  8. POJ 2954 /// 皮克定理+叉积求三角形面积

    题目大意: 给定三角形的三点坐标 判断在其内部包含多少个整点 题解及讲解 皮克定理 多边形面积s = 其内部整点in + 其边上整点li / 2 - 1 那么求内部整点就是 in = s + 1 - ...

  9. Startup里面的一些用法

    using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; usi ...

  10. 解决jquery ajax在跨域访问post请求的时候,ie9以下无效(包括ie9)的问题

    最近在做项目的时候遇到一个问题,就是跨域请求ajax的时候ie9以下的浏览器不可以访问,直接执行error里面的代码,但是也不报错,就上网查了查,发现了一个很好用的方法,在这里记录一下,也希望可以帮到 ...