前端交互效果怎样进行前端模块化和组件化管理?

更多公众号:xuebing_wxb传播与学习最新文章相关推荐搜狗:感谢您阅读做了这么久的前端开发,听过Css模块化开发么?,本文可能来自网络,如果侵犯了您的相关权益,请联系管理员。QQ:闲聊——浅谈前端js模块化演变 - 推酷
闲聊——浅谈前端js模块化演变
function时代
前端这几年发展太快了,我学习的速度都跟不上演变的速度了(门派太多了,后台都是大牛公司支撑类似于facebook的react、google的angular,angular的1.0还没怎么用过项目,网上查阅2.0的正式版就要出来,书写方法大改,思维架构都有很大的改变,真是难为了现在的前端)。2010年第一次接触前端js,还是从asp.net拖控件中接触,再接着就是我大学那个时代最出名的传智播客视频教学,那个时候课余时间全去看这个视频了,对着教学一个一个的敲,依稀的记得好定义了好多function,现在想想还是很有趣,心想反正就几个方法也不会重复。
Object,Function的prototype时代
随着前端的代码越写越多(自己偶尔会和朋友一起接点外包或帮老师做点项目,毕竟学了不用,永远也只是纸上谈兵),发现自己词穷了,自己定义的function名称太多了(方法重名可是会覆盖之前的方法),这个时候怎么办了,在学校最好一点是什么,就是几乎每个学校都有图书馆,你都能找到自己想要的书籍,因为我本身大学主专业是学习C#的,js这种弱类型语言不停的写function太不美观了(自黑一下,其实我是让人讨人厌的处女座),图书馆有很多js设计模式的书籍,js高级编程,写的都很不错,到现在项目中也都没有完全的用到,有些可能用到了吧,可是都不记得这些专业术语名词(现在什么设计模式,什么新技术的缩写名词太多了,有些虽然用过,可就是就不住。记不住又不行,有些面试官就是喜欢问,不知道你可就惨了,有些更可笑的是考官在网上现查的,然后立即来问你,'哈哈,其实我也做过这种事')。虽然我是一个大懒人可是看多了,至少也是会记住一两个,用Function的prototype和arguments去搞面向对象还是很有趣的,因为是弱类型,所以很多写法更灵活。如果你想说你更懒,那你就Object里面定义一大顿方法也行,其实这种写法在现在也是很流行,比如我们常用的工具类。
好的程序员不是一个人独自敲代码,闭门造车,我们多去查看新技术、新框架、新组建(
不过这也确实难为很多人,毕竟互联网是一个多姿多彩的世界。幸好随着时代的进步,我们看书学技术的途径也越来越多了,刚开始我关注过一些有趣技术网站的qq账号,每天都可以在我们逛QQ空间的时候,看到几条很有趣翻译的外国技术分享文章,再后来有朋友推荐我去看各大公司技术论坛网站,不过这个没看多久,太多了,好坏难分,重叠的太多了。移动互联网发展越来越快,微信火得一塌糊涂,几个微信前端公共账号还是不错的,每天都会推荐一篇不错的文章,公共号为’前端早读课‘,’前端大全‘
),个人认为好的程序员都应该有拿来主义和创新精神,所以我们引用的框架越来越多,好多框架都是一个js文件,它们都怕自己的代码被污染,所以大多数用到了闭包,那什么是闭包了,闭包有什么好处呢,网上有好多,在这里我也啰嗦几句。
闭包的好处:
1. 逻辑连续,当闭包作为另一个函数调用的参数时,避免你脱离当前逻辑而单独编写额外逻辑。
2. 方便调用上下文的局部变量。
3. 加强封装性,第2点的延伸,可以达到对变量的保护作用。
闭包的坏处:
闭包有一个非常严重的问题,那就是内存浪费问题,这个内存浪费不仅仅因为它常驻内存,更重要的是,对闭包的使用不当会造成无效内存的产生。
优化注意:
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便
只要你搞前端,或者搞web几乎都有人问你,几率几乎达到80%,这个时候推荐一篇博客(
),这可是汤姆大叔,本身非常的佩服他,他写的js设计模式和js注意事项确实不错,就在博客园中,也很感谢这些人在博客园中,我们大学生活才更幸福。
js模块化和MVC
Extjs或sencha touch这两个都是同一家公司的,也是我用到的最早的前端模块化和MVC,sencha touch我用的也是最多的,因为移动端毕竟火爆。
说的它的好处吧:
1.灵活架构,焦点分离
2.方便模块间组合、分解
3.方便单个模块功能调试、升级
4.多人协作互不干扰
mvc是后端说的最多的术语,如果你现在还不懂你最好快点去恶补下,因为现在很多形形色色的前端MVC层出不穷,
MVC开始是存在于桌面程序中的,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。比如一批统计数据可以分别用柱状图、饼图来表示。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。
MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式:
Model(模型)表示应用程序核心(比如数据库记录列表)。
View(视图)显示数据(数据库记录)。
Controller(控制器)处理输入(写入数据库记录)。
MVC 模式同时提供了对 HTML、CSS 和 JavaScript 的完全控制。
Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。
通常模型对象负责在数据库中存取数据。
View(视图)是应用程序中处理数据显示的部分。
通常视图是依据模型数据创建的。
Controller(控制器)是应用程序中处理用户交互的部分。
通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
MVC 分层有助于管理复杂的应用程序,因为您可以在一个时间内专门关注一个方面。例如,您可以在不依赖业务逻辑的情况下专注于视图设计。同时也让应用程序的测试更加容易。
MVC 分层同时也简化了分组开发。不同的开发人员可同时开发视图、控制器逻辑和业务逻辑。
啰嗦一点说一下sencha这家js框架公司的好处和弊端吧,他们提供的框架有很好的样式体系,基于sass写的,可以随便我们改变样式风格,提供的sencha.cmd第一次让我感觉到了前端的工程化,提供了代码的压缩、代码验证、代码模块的依赖合并。组件丰富,说了这么多大家感觉一定很爽吧。但是由于他提供非常多的组件,所以导致js代码过多,虽然有些我们可以自行配置筛选压缩,它的依赖压缩不是全部根据配置,大部门和文件夹里面的文件有关,必须不停的移除或添加,反正就是很麻烦,特别是版本的升级时候,真是想吐了。有时因为压缩的缘故还会报一些下错。
AMD和CMD时代
说来前面的大框架我们一定想用到更加轻便的模块框架了,这个时候一定要说说两派的代表框架RequireJS和SeaJs,引用一下github上的专业术语吧,个人也经过一段时间的验证。
RequireJS 和 Sea.js 都是模块加载器,倡导模块化开发理念,核心价值是让 JavaScript 的模块化开发变得简单自然。
两者的主要区别如下:
定位有差异。RequireJS 想成为浏览器端的模块加载器,同时也想成为 Rhino / Node 等环境的模块加载器。Sea.js 则专注于 Web 浏览器端,同时通过 Node 扩展的方式可以很方便跑在 Node 环境中。
遵循的规范不同。RequireJS 遵循 AMD(异步模块定义)规范,Sea.js 遵循 CMD (通用模块定义)规范。规范的不同,导致了两者 API 不同。Sea.js 更贴近 CommonJS Modules/1.1 和 Node Modules 规范。
推广理念有差异。RequireJS 在尝试让第三方类库修改自身来支持 RequireJS,目前只有少数社区采纳。Sea.js 不强推,采用自主封装的方式来“海纳百川”,目前已有较成熟的封装策略。
对开发调试的支持有差异。Sea.js 非常关注代码的开发调试,有 nocache、debug 等用于调试的插件。RequireJS 无这方面的明显支持。
插件机制不同。RequireJS 采取的是在源码中预留接口的形式,插件类型比较单一。Sea.js 采取的是通用事件机制,插件类型更丰富。
总之,如果说 RequireJS 是 Prototype 类库的话,则 Sea.js 致力于成为 jQuery 类库。
webpack时代
Seajs我没怎么用过项目,所以也就不说了,RequireJS 用过,那时候用的.net的mvc5.0中的一个第三方插件,帮我省去了很多的配置文件,因为如果我们用nodejs的话一般要自己书写R.js,用来配置一些处理流程,强大的.net插件帮我省去了好多,可是每个模块你都的定义,并且在配置文件中书写出来,每个模块都要写初始模块定义,为什么我会这么去说话一个框架了,因为不断的学习用到了更好的webpack,以下是我的观点(有些解释术语参考了其它博客)
说说一下webpack的优点吧:
1.require.js的所有功能它都有
2.编绎过程更快,因为require.js会去处理不需要的文件
3.还有一个额外的好处就是你不需要再做一个封装的函数,require.js中你得这样
define(['jquery'], function(jquery){})
4.现在你需要一个很大的封装去定义每个模块,然后你需要在在require.js的配制文件中将每个模块的路径都配出来,用过requirejs都会遇到的好繁琐
require.config({
baseUrl: '/scripts',
'facebook'
: '//connect.facebook.net/en_US/all',
// 'facebook'
: '//connect.facebook.net/en_US/sdk/debug'
'requirejs'
: '../bower_components/requirejs/require',
: '../bower_components/react/react-with-addons',
'underscore'
: '../bower_components/lodash/dist/lodash',
'futures-requirejs' : '../bower_components/futures-requirejs/future',
: '../bower_components/jquery/jquery',
// 'phaser'
: '../bower_components/phaser/build/phaser',
'phaser.filters'
: '../bower_components/phaser/filters/',
: '../thirdParty/phaser/Phaser',
: '../bower_components/Snap.svg/dist/snap.svg',
: '../thirdParty/Proton',
'copyProperties'
: '../thirdParty/copyProperties',
: '../bower_components/flux/dist/Flux',
'eventEmitter'
: '../bower_components/eventEmitter/EventEmitter',
: '../bower_components/pixi/bin/pixi',
'crossroads'
: '../bower_components/crossroads/dist/crossroads',
: '../bower_components/js-signals/dist/signals',
: '../bower_components/hasher/dist/js/hasher',
: '../bower_components/async/lib/async',
'socket.io-client'
: '../bower_components/socket.io-client/dist/socket.io',
'html2canvas'
: '../bower_components/html2canvas/build/html2canvas.min',
: '../bower_components/hammerjs/hammer',
'touch-emulator'
: '../bower_components/hammer-touchemulator/touch-emulator',
: '../bower_components/moment/moment',
// 'famous'
: '../bower_components/famous',
'tinygradient'
: '../bower_components/tinygradient/tinygradient',
: '../bower_components/page/index',
// 'faker'
: '../bower_components/faker/dist/faker',
: '../thirdParty/Faker',
: '../thirdParty/Perlin',
'tinycolor'
: '../vendors/tinycolor',
: '../../node_modules/flux/index',
: './errors',
: '../../server',
packages: [{
location : '../bower_components/api2/src/',
'phaser.filters/Fire': {
deps: ['phaser'],
exports: 'page'
'snap' : {
exports: 'Snap'
'html2canvas' : {
exports: 'html2canvas'
'facebook' : {
exports: 'FB'
// 'underscore': {
exports: '_'
'phaser': {
exports: 'Phaser'
exports: 'PIXI'
'hammer': {
exports: 'Hammer'
'touch-emulator': {
exports: 'TouchEmulator'
'proton': {
exports: 'Proton'
'moment': {
exports: 'moment'
以下是webpack的一个文件配置,
var path = require("path");
var webpack = require("webpack");
var ExtractTextPlugin = require("extract-text-webpack-plugin")
module.exports = {
// context: path.join(__dirname),
index: './app/scripts/index.js',
page1: './app/scripts/page1.js',
page3: './app/scripts/page3.js'
path: path.join(__dirname, '_dist'),
filename: './scripts/[name]-bundle.js',
chunkFilename: "./scripts/[id]-chunk.js",
// library:'appConfig'
//主要应用jsonp命名重新定义
loaders: [{
test: /\.css$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader")
test: /\.less$/,
loader: 'style-loader!css-loader!less-loader'
test: /\.woff$/,
loader: 'url-loader?prefix=font/&limit=5000'
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
compact: false
'html-minify-loader': {
empty: true, // KEEP empty attributes
cdata: true, // KEEP CDATA from scripts
comments: true // KEEP comments
resolve: {
root: [path.join(__dirname, "bower_components"), path.join(__dirname, 'app', 'scripts')],
plugins: [
new monsChunkPlugin({
name: "commons",
filename: "./scripts/commons.js",
chunks: ["page1", "page2", "page3"]
new ExtractTextPlugin("./styles/[name].css"),
new webpack.ResolverPlugin(
new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
我们可以发现少了好多引用模块js文件路径引用,可能会有人问,它怎么知道我要引用那些js,在nodejs里有一个有趣的插件brower(这东西你如果没有用到,你老板可能会说你还是一个初级菜鸟)
Bower 是twitter 推出的一款包管理工具,基于nodejs的模块化思想,把功能分散到各个模块中,让模块和模块之间存在联系,通过 Bower 来管理模块间的这种联系
包管理工具一般有以下的功能:
注册机制:每个包需要确定一个唯一的 ID 使得搜索和下载的时候能够正确匹配,所以包管理工具需要维护注册信息,可以依赖其他平台。
文件存储:确定文件存放的位置,下载的时候可以找到,当然这个地址在网络上是可访问的。
上传下载:这是工具的主要功能,能提高包使用的便利性。比如想用 jquery 只需要 install 一下就可以了,不用到处找下载。上传并不是必备的,根据文件存储的位置而定,但需要有一定的机制保障。
依赖分析:这也是包管理工具主要解决的问题之一,既然包之间是有联系的,那么下载的时候就需要处理他们之间的依赖。下载一个包的时候也需要下载依赖的包
可能会有人会问,我虽然将这些包下了下来,那我还是不知道那些模块位置,我该如果引用了,webpack一个插件轻松解决这个问题:以下是配置文件
resolve: {
  root: [path.join(__dirname, "bower_components"), path.join(__dirname, 'app', 'scripts')],
plugins: [
  new webpack.ResolverPlugin(
    new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
那如果调用了
var $ = require("jquery");
是不是感觉很方便了,还有一些新手可能会吐槽,js本来就是弱类型语言,框架那么多,智能提示是不是很差,特别是玩微软那套玩多了的人一定会问,在此推荐以下webstorm、sublime、atom它们上面的插件还是不错的
5.requirejs它是异步依赖加载的,说白了就是,只要你用到了,它绝对会一次性加载完,就算你初始化没有用到,它也会加载,如果你把它压缩,文件就好大了,最后就一个文件。你也可以破坏它的原则,按传统的写法单独加载,不过就整体就不是很美观了。可能有些解决的插件,我没用到也是有可能的,这里也就不多说了。
webpakc就很好解决了,它提供的插件可以自动分析,根据你提过js文件主入口,自动分析,可合成多个js文件,但是它不会全部加载,按照你的需要一次加载,这样就不会出现页面刚初始化就加载不必要的js文件,提高页面速度(虽然可以靠用体力解决,说白了就是注意写法,不过好痛苦)
以上是它们的对比,再说说它的私有特性吧
1. 对 CommonJS 、 AMD 、ES6的语法做了兼容
2. 对js、css、图片等资源文件都支持打包(css都可以合成多个css文件包,好爽,再也不是sb似的全部加载了,sass和less虽然也是模块化的加载合并,可是css和js分离的关联不大,这里的css可以和js有更大的关联,更细致区分加载的js)
3. 串联式模块加载器以及插件机制,让其具有更好的灵活性和扩展性,例如提供对CoffeeScript、ES6的支持
4. 有独立的配置文件webpack.config.js
5. 可以将代码切割成不同的chunk,实现按需加载,降低了初始化时间
6. 支持 SourceUrls 和 SourceMaps,易于调试
7. 具有强大的Plugin接口,大多是内部插件,使用起来比较灵活
8.webpack 使用异步 IO 并具有多级缓存。这使得 webpack 很快且在增量编译上更加快
在补充一个特别的属性吧
双服务器模式
项目开发中,仅有一台静态服务器是不能满足需求的,我们需要另启一台web服务器,且将静态服务器集成到web服务器中,就可以使用webpack的打包和加载功能。我们只需要修改一下配置文件就可以实现服务器的集成。
'./src/page/main.js',
'webpack/hot/dev-server',
'webpack-dev-server/client?http://127.0.0.1:8080'
path: __dirname,
filename: '[name].js',
publicPath: &http://127.0.0.1:8080/assets/&
plugins: [
new webpack.HotModuleReplacementPlugin()
如果在开发中启动两个服务器并不是一个很好地选择,webpack提供了一个中间件webpack-dev-middleware,但其只能在生产环境中使用,可以实现在内存中实时打包生成虚拟文件,供浏览器访问以及调试。使用方式如下:
var webpackDevMiddleware = require(&webpack-dev-middleware&);
var webpack = require(&webpack&);
var compiler = webpack({
// configuration
output: { path: '/' }
app.use(webpackDevMiddleware(compiler, {
// options
有些好处可能没有说到,webpack可能过几年它就会被取代也是有可能,但是现在如果你说你不会,那就请赶快恶补吧,它会带你飞的。
以上分析结合自己工作经验之谈,有些可能说大呢,说错了大家就一笑而过,不对的地方也希望诚恳指出。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致前端模块化 (好文分享)_Javascript教程-织梦者
当前位置:&>&&>& > 前端模块化 (好文分享)
前端模块化 (好文分享)
本文将为关注织梦者的朋友提供的是的前端模块化 (好文分享)相关教程,具体实例代码请看下文:
前端模块化
在JavaScript发展初期就是为了实现简单的页面交互逻辑,寥寥数语即可;如今CPU、性能得到了极大的提升,很多页面逻辑迁移到了客户端(表单验证等),随着web2.0时代的到来,Ajax技术得到广泛应用,jQuery等前端库层出不穷,前端代码日益膨胀
这时候JavaScript作为嵌入式的脚本语言的定位动摇了,JavaScript却没有为组织代码提供任何明显帮助,甚至没有类的概念,更不用说模块(module)了,JavaScript极其简单的代码组织规范不足以驾驭如此庞大规模的代码
既然JavaScript不能handle如此大规模的代码,我们可以借鉴一下其它语言是怎么处理大规模程序设计的,在Java中有一个重要带概念&&,逻辑上相关的代码组织到同一个包内,包内是一个相对独立的王国,不用担心命名冲突什么的,那么外部如果使用呢?直接对应的package即可
遗憾的是JavaScript在设计时定位原因,没有提供类似的功能,开发者需要模拟出类似的功能,来隔离、组织复杂的JavaScript代码,我们称为模块化。
一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。模块开发需要遵循一定的规范,各行其是就都乱套了
规范形成的过程是痛苦的,前端的先驱在刀耕火种、茹毛饮血的阶段开始,发展到现在初具规模,简单了解一下这段不凡的历程
我们在讲函数的时候提到,函数一个功能就是实现特定逻辑的一组语句打包,而且JavaScript的作用域就是基于函数的,所以把函数作为模块化的第一步是很自然的事情,在一个文件里面编写几个相关函数就是最开始的模块了
这样在需要的以后夹在函数所在文件,调用函数就可以了
这种做法的缺点很明显:污染了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间没什么关系。
为了解决上面问题,对象的写法应运而生,可以把所有的模块成员封装在一个对象中
这样我们在希望调用模块的时候引用对应文件,然后
这样避免了变量污染,只要保证模块名唯一即可,同时同一模块内的成员也有了关系
看似不错的解决方案,但是也有缺陷,外部可以随意修改内部成员
这样就会产生意外的安全问题
立即执行函数
可以通过立即执行函数,来达到隐藏细节的目的
var myModule = (function(){ var var1 = 1; var var2 = 2; function fn1(){ } function fn2(){ } return { fn1: fn1, fn2: fn2 }; })();
这样在模块外部无法修改我们没有暴露出来的变量、函数
上述做法就是我们模块化的基础,目前,通行的JavaScript模块规范主要有两种:和CommonJS
我们先从CommonJS谈起,因为在网页端没有模块化编程只是页面JavaScript逻辑复杂,但也可以工作下去,在服务器端却一定要有模块,所以虽然JavaScript在web端发展这么多年,第一个流行的模块化规范却由服务器端的JavaScript应用带来,CommonJS规范是由NodeJS发扬光大,这标志着JavaScript模块化编程正式登上舞台。
根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性
模块输出:
模块只有一个出口,对象,我们需要把模块希望输出的内容放入该对象
加载模块:
加载模块使用方法,该方法读取一个文件并执行,返回文件内部的对象
//模块定义 myModel.js var name = 'Byron'; function printName(){ console.log(name); } function printFullName(firstName){ console.log(firstName + name); } module.exports = { printName: printName, printFullName: printFullName } //加载模块 var nameModule = require('./myModel.js'); nameModule.printName();
不同的实现对require时的路径有不同要求,一般情况可以省略拓展名,可以使用相对路径,也可以使用绝对路径,甚至可以省略路径直接使用模块名(前提是该模块是系统内置模块)
尴尬的浏览器
仔细看上面的代码,会发现是同步的。模块系统需要同步读取模块文件内容,并编译执行以得到模块接口。
这在服务器端实现很简单,也很自然,然而, 想在浏览器端实现问题却很多。
浏览器端,加载JavaScript最佳、最容易的方式是在document中插入标签。但脚本标签天生异步,传统CommonJS模块在浏览器环境中无法正常加载。
解决思路之一是,开发一个服务器端组件,对模块代码作静态分析,将模块与它的依赖列表一起返回给浏览器端。 这很好使,但需要服务器安装额外的组件,并因此要调整一系列底层架构。
另一种解决思路是,用一套标准模板来封装模块定义,但是对于模块应该怎么定义和怎么加载,又产生的分歧:
AMD 即,中文名是异步模块定义的意思。它是一个在浏览器端模块化开发的规范
由于不是JavaScript原生支持,使用AMD规范进行页面开发需要用到对应的库函数,也就是大名鼎鼎,实际上AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出
requireJS主要解决两个问题
多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长
看一个使用requireJS的例子
// 定义模块 myModule.js define(['dependency'], function(){ var name = 'Byron'; function printName(){ console.log(name); } return { printName: printName }; }); // 加载模块 require(['myModule'], function (my){
  my.printName();
requireJS定义了一个函数 define,它是全局变量,用来定义模块
id:可选参数,用来定义模块的标识,如果没有提供该参数,脚本文件名(去掉拓展名)
dependencies:是一个当前模块依赖的模块名称数组
factory:工厂方法,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值
在页面上使用函数加载模块
require()函数接受两个参数
第一个参数是一个数组,表示所依赖的模块
第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块
require()函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。
CMD 即通用模块定义,CMD规范是国内发展出来的,就像AMD有个requireJS,CMD有个浏览器的实现SeaJS,SeaJS要解决的问题和requireJS一样,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同
Sea.js 推崇一个模块一个文件,遵循统一的写法
因为CMD推崇
一个文件一个模块,所以经常就用文件名作为模块id
CMD推崇依赖就近,所以一般不在define的参数中写依赖,在factory中写
factory有三个参数
require 是 factory 函数的第一个参数
require 是一个方法,接受 模块标识 作为唯一参数,用来获取其他模块提供的接口
exports 是一个对象,用来向外提供模块接口
module 是一个对象,上面存储了与当前模块相关联的一些属性和方法
// 定义模块 myModule.js define(function(require, exports, module) { var $ = require('jquery.js') $('div').addClass('active'); }); // 加载模块 seajs.use(['myModule.js'], function(my){ });
AMD与CMD区别
关于这两个的区别网上可以搜出一堆文章,简单总结一下
最明显的区别就是在模块定义时对依赖的处理不同
AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
CMD推崇就近依赖,只有在用到某个模块的时候再去require
这种区别各有优劣,只是语法上的差距,而且requireJS和SeaJS都支持对方的写法
AMD和CMD最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同
很多人说requireJS是异步加载模块,SeaJS是同步加载模块,这么理解实际上是不准确的,其实加载模块都是异步的,只不过AMD依赖前置,js可以方便知道依赖模块是谁,立即加载,而CMD就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块,这也是很多人诟病CMD的一点,牺牲性能来带来开发的便利性,实际上解析模块用的时间短到可以忽略
为什么我们说两个的区别是依赖模块执行时机不同,为什么很多人认为ADM是异步的,CMD是同步的(除了名字的原因。。。)
同样都是异步加载模块,AMD在加载模块完成后就会执行改模块,所有模块都加载执行完后会进入require的回调函数,执行主逻辑,这样的效果就是依赖模块的执行顺序和书写顺序不一定一致,看网络速度,哪个先下载下来,哪个先执行,但是主逻辑一定在所有依赖加载完成后才执行
CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的
这也是很多人说AMD用户体验好,因为没有延迟,依赖模块提前执行了,CMD性能好,因为只有用户需要的时候才执行的原因
转自/dolphinX/p/4381855.html谢谢您的访问.
这些内容可能对你也有帮助
更多可查看Javascript教程列表页。
猜您也会喜欢这些文章

我要回帖

更多关于 前端模块化的理解 的文章

 

随机推荐