JS异步那些事 五 (异步脚本加载)

JS异步那些事 一 (基础知识)
JS异步那些事 二 (分布式事件)
JS异步那些事 三 (Promise)
JS异步那些事 四(HTML 5 Web Workers)
JS异步那些事 五 (异步脚本加载)javascript

异步脚本加载

阻塞性脚本

JavaScript在浏览器中被解析和执行时具备阻塞的特性,也就是说,当JavaScript代码执行时,页面的解析、渲染以及其余资源的下载都要停下来等待脚本执行完毕前端

浏览器是按照从上到下的顺序解析页面,所以正常状况下,JavaScript脚本的执行顺序也是从上到下的,即页面上先出现的代码或先被引入的代码老是被先执行,即便是容许并行下载JavaScript文件时也是如此。注意咱们这里标红了"正常状况下",缘由是什么呢?咱们知道,在HTML中加入JavaScript代码有多种方式,归纳以下(不考虑require.js或sea.js等模块加载器):java

(1)正常引入:即在页面中经过<script>标签引入脚本代码或者引入外部脚本
(2)经过document.write方法向页面写入<script>标签或代码
(3)经过动态脚本技术,即利用DOM接口建立<script>元素,并设置元素的src,而后再将元素添加进DOM中。
(4)经过Ajax获取脚本内容,而后再建立<script>元素,并设置元素的text,再将元素添加进DOM中。
(5)直接把JavaScript代码写在元素的事件处理程序中或直接做为URL的主体git

具体参考 http://www.jb51.net/article/77920.htmes6

脚本延迟运行

通常在JS页面延迟执行一些方法。可使用如下的方法:github

Window.setTimeout  

jQuery.delay

jQuery.queue和jQuery.dequeue
<script src="deferdemo.js" defer></script>

加上 defer 等于在页面彻底在入后再执行,至关于 window.onload ,但应用上比 window.onload 更灵活!segmentfault

<script type="text/javascript" src="demo_async.js" async="async"></script>

使用async属性,浏览器会下载js文件,同时继续对后面的内容进行渲染
一般若是js不须要改变DOM结构时可使用async进行异步加载(好比一些统计代码能够异步加载,由于此代码与页面执行逻辑无关,不会改变DOM结构)api

SeaJS与RequireJS

网上写amd和cmd的文章不少,固然也有不少都是误人子弟的片面的见解,因此仍是推荐本身看官方文档多加尝试去理解。浏览器

“RequireJS 遵循的是 AMD(异步模块定义)规范,SeaJS 遵循的是 CMD (通用模块定义)规范”。缓存

AMD 是 RequireJS 在推广过程当中对模块定义的规范化产出。
CMD 是 SeaJS 在推广过程当中对模块定义的规范化产出。

amd 规划 https://github.com/amdjs/amdjs-api/wiki/AMD-(%E4%B8%AD%E6%96%87%E7%89%88)

cmd 规范 https://github.com/seajs/seajs/issues/242

区别:

  1. 对于依赖的模块,AMD 是提早执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改为能够延迟执行(根据写法不一样,处理方式不一样)

  2. CMD 推崇依赖就近,AMD 推崇依赖前置。

ECMAScript6 Moudle

历史上,JavaScript一直没有模块(module)体系,没法将一个大程序拆分红互相依赖的小文件,再用简单的方法拼装起来。其余语言都有这项功能,好比Ruby的require、Python的import,甚至就连CSS都有@import
到了ES6,实现了模块化的功能,功能上基本能够取代 cmd和amd的规范,

模块的功能主要由两个命令构成,export和import,export命令用于规定模块的对外接口,import命令用于输入其余模块提供的功能。

export的写法,

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {firstName, lastName, year};

上面代码在export命令后面,使用大括号指定所要输出的一组变量。

import写法:

// main.js

import {firstName, lastName, year} from './profile';

function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}

ES6模块加载的实质

ES6模块加载的机制,与CommonJS模块彻底不一样。CommonJS模块输出的是一个值的拷贝,而ES6模块输出的是值的引用。CommonJS模块输出的是被输出值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。

ES6模块的运行机制与CommonJS不同,它遇到模块加载命令import时,不会去执行模块,而是只生成一个动态的只读引用。等到真的须要用到时,再到模块里面去取值,换句话说,ES6的输入有点像Unix系统的”符号链接“,原始值变了,import输入的值也会跟着变。所以,ES6模块是动态引用,而且不会缓存值,模块里面的变量绑定其所在的模块。

// mod.js
function C() {
  this.sum = 0;
  this.add = function () {
    this.sum = 1;
  };
  this.show = function () {
    console.log(this.sum);
  }
}

export let c = new C();

上面的脚本mod.js,输出的是一个C的实例。不一样的脚本加载这个模块,获得的都是同一个实例。

// x.js
import {c} from './mod';
c.add();

// y.js
import {c} from './mod';
c.show();

// main.js
import './x';
import './y';

如今执行main.js,输出的是1。
证实加载的是同一个实例
参考 http://es6.ruanyifeng.com/#docs/module

总结

写这篇博客参考了不少网上的文章和一些书籍,由于太多就没有一一列举,这也算是我学习js异步知识的一个记录吧。

毕竟立刻就要去以一个前端工程师的身份去鹅厂实习了,因此仍是要多学点东西,拿点干货出来。

关于JS异步那些事就写到这里了,不少地方理解的不够深入但愿你们多多指教。

相关文章
相关标签/搜索