RequireJS

JavaScript模块化实现方案:CommonJSCMD规范AMD规范ES6-module

CommonJS:node.js模块机制参照者,用于服务端编程,模块是同步加载的,因为在服务器本机所以模块间读写速度快。

CMD规范:sea.js,推崇依赖就近原则,CMD的依赖是按需加载的,定义一个模块时不需要立即声明依赖模块,在模块中需要使用其他依赖模块时require该依赖就可以了。

AMD规范:require.js,推崇依赖前置原则。AMD定义一个模块时需要声明依赖模块,并将模块ID以形参方式传入factory函数中,当然在AMD模块中也能使用CMD的语法,依赖模块在运行中使用require来加载使用。

ES6-module:是ES6推出后前端常用的模块化实现方案。

本文详细介绍AMD规范及require.js(JS模块化工具、模块加载器)

· 客户端前端文件是部署在服务器上的,如果使用common.js同步加载模块,受网速等影响使模块加载缓慢导致页面白屏无响应等情况出现,JS加载阻塞页面的渲染,为解决该问题推出了AMD规范(异步模块定义)浏览器客户端模块化的实现。

· 模块定义了一个作用域,避免全局空间的污染,无需使用全局变量,通过define参数形式注入依赖模块,可以实现在同一个页面同时加载同一模块的不同版本。

AMD的优点:

1.小巧轻量,文件体积小;

2.灵活,可搭配其他框架或库实现模块化;

3.异步加载模块,防止js加载阻塞页面的渲染;

4.加载js更加方便简洁,替代老式的script标签按依赖顺序引入js文件,使用require()方法就可以实现js文件的加载,内部原理使用head.appendChild()方法将每一个依赖模块创建script标签并按路径原则加载js模块;

5.功能函数封装使用,更好的实现模块复用,模块间互不影响;

6.模块文件可按需加载并懒加载,例如当事件触发或调用到该模块函数时才加载对应模块,或在程序运行中通过require()来加载,避免了初始化时大量的文件请求与数据传输影响页面渲染;

require.js的使用介绍:

在require.js的官网下载require.js文件

· defer和async="true"实现require.js的异步加载,defer属性兼容IE

· data-main属性相当于requirejs的入口js,在requirejs加载完后加载,常放置全局配置等,requirejs默认模块文件后缀为.js,所以可以省略.js后缀

· requirejs使用define()来定义一个模块,一个js文件就是一个模块,使用require()来加载依赖模块并执行加载完毕后的回调函数,这个过程是异步的

· define(id?, dependencies?, factory)

· 简单的键值对模块定义define({name: 'IT小猿人', sex: '男', fn: function(){}})

· 键值对模块函数定义define(function(){return {name: 'IT小猿人', age: 25};})

· define定义模块需return一个值,可以是对象、函数等,对外暴露提供模块的属性和方法,不在return中的为模块私有属性和方法,不能在require的回调函数中通过模块ID访问调用

· 无依赖模块定义define(function(){})

· 有依赖模块定义define(['a', 'b'], function(a, b){})当前模块依赖a和b两个模块,当依赖多个模块时可以使用参数require来处理

define(function(require){var m1 = require('m1'), m2 = require('m2')...})

· define的第一个可选参数id表示命名模块,模块定义时指定了模块名称,这样在requirejs中require.config中设置paths或模块中使用这个命名模块作为依赖时模块ID都是唯一的、相同的(都是这个id值),不能写其他名称,例如jquery中定义了模块名define('jquery', [], function(){}),这样的好处就是在其他所有有使用该模块的地方都是同一个模块的引用,这样程序只会加载一次该命名模块(注:如若真要去改变它,将这个命名模块自定义名称可以使用shim,此处不作介绍,因为不推荐这么做)

· 当省略了id这个参数就是无命名模块,模块ID可以随意定义,较为灵活

· 模块内使用require异步加载模块时存在的问题

eg: merge.js

模块内调用:

打印出来是个空值,解决办法可以使用promise来处理

 

 

打印出来为hello world

· require([], factory, errFn)

参数一为加载的模块,为数组格式

参数二为模块加载完成所执行的回调函数,形参为参数一模块依次对应的ID,若某个模块没有输出变量可省略,但要保证顺序对应

参数三为加载失败所执行的错误回调函数,例如某个模块加载失败或属性方法不可访问或不存在

参数一数组中可以写表达式,例如判断某个条件情况下加载不同的模块

当省略了第三个错误回调函数时,可以使用全局错误监听函数,当第三个错误回调函数未捕获到的错误都会触发该全局函数来捕获

require.onError = function(err){/* do something */}

· 当一个模块使用了另一个模块的变量或方法,则需要使用require嵌套使用

例如

· main.js通常存放require的配置信息require.config({})接收一个对象参数

 

 

· 模块加载路径规则:

如上data-main="js/main"当未指定baseUrl时,require加载模块的基础路劲为js/;当指定了baseUrl时以baseUrl路径为准;当baseUrl和data-main都未指定时则以引入requirejs的html文件所在的路径为基础路径;

· 使用require(['a', 'b', 'c'], function(a, b, c){})加载模块时,会发起三次请求,requirejs提供了一个优化器r.js,当模块部署完后可以将多个模块合并压缩到一个文件中,避免加载多个模块发起多次http请求影响网页加载速度。

· requirejs提供了很多插件供使用

domready插件让回调函数在DOM加载完毕后再执行

require(['domready!'], function(doc){})

text插件允许requirejs加载文本

require(['text!'], function(text){})

image插件允许requirejs加载图片

require(['image!'], function(image){})

还有json,mdown加载json、markdown文件

更多插件请查看https://github.com/jrburke/requirejs/wiki/Plugins

· 循环依赖问题(两个模块相互依赖)

解决方法一:将一个模块改为运行时通过require加载

解决方法二:注入exports解决

解决方法三:使用commonjs规范

 

posted @ 2021-05-15 17:51  IT小猿人  阅读(705)  评论(0编辑  收藏  举报