前端为什么需要模块化开发

栏目: JavaScript · 发布时间: 4年前

内容简介:看着上面的script标签,是不是有一种很熟悉的感觉。通过script引入你想要的资源,从上到下的顺序,这其中顺序是非常重要的,资源的加载先后决定你的代码是否能够跑的下去。当然我们还没有加入defer和async属性,不然加载的逻辑会更加复杂。这里引入的资源还是算少的,过多的script标签会造成过多的请求。同时项目越大,到最后依赖会越来越复杂,并且难以维护,依赖模糊,请求过多。全局污染的可能性就会更大。那么问题来了,如何形成独立的作用域?defer要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,
前端为什么需要模块化开发

看着上面的script标签,是不是有一种很熟悉的感觉。通过script引入你想要的资源,从上到下的顺序,这其中顺序是非常重要的,资源的加载先后决定你的代码是否能够跑的下去。当然我们还没有加入defer和async属性,不然加载的逻辑会更加复杂。这里引入的资源还是算少的,过多的script标签会造成过多的请求。同时项目越大,到最后依赖会越来越复杂,并且难以维护,依赖模糊,请求过多。全局污染的可能性就会更大。那么问题来了,如何形成独立的作用域?

defer和async的区别

defer要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行;async一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。一句话,defer是“渲染完再执行”,async是“下载完就执行”。另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。

模块化的基石

立即执行函数(immediately-invoked function expression),简称IIFE,其实是一个javaScript函数。可以在函数内部定义方法以及 私有属性 ,相当于一个封闭的作用域。例如下面的代码:

let module = (function(){
    let _private = 'myself';
    let fun = () =>{
        console.log(_private)
    }
    return {
        fun:fun
    }
})()
module.fun()//myself
module._private//undefined
复制代码

以上代码便可以形成一个独立的作用域,一定程度上可以减少全局污染的可能性。这种写法可是现代模块化的 基石 。虽然能够定义方法,但是不能定义属性,这时候各种前端规范就陆续登场了。

首先登场的是common.js

最先遵守CommonJS规范是node.js。这次变革让服务端也能用js爽歪歪的写了,我们的javaScript并不止于浏览器,服务端也能分一杯羹,被人称为模块化的第一座里程碑。想想长征二万五,第一座里程碑在哪里?

CommomJS模块的特点

  • 模块内的代码只会运行在模块作用域内,不会污染到全局作用域
  • 模块的可以多次引入,但只会在第一次加载的时候运行一次,后面的运行都是取缓存的值。想要让模块再次运行,必须清楚缓存。
// 删除指定模块的缓存
delete require.cache[moduleName];

// 删除所有模块的缓存
Object.keys(require.cache).forEach(function(key) {
  delete require.cache[key];
})
复制代码
  • 模块的加载顺序,遵循在代码中出现的顺序。

为什么要少用exports

exports只是一个变量,指向module.exports,也就是exports只是一个 引用 而已。所以对外输出模块的时候,我们就可以通过exports添加方法和和属性。通过module.exports对外输出其实也是读取module.exports的变量。但是使用exports时要非常的小心,因为稍不注意就会切断和module.exports的联系。例如:

exports = function(x) {console.log(x)};
复制代码

上面的代码运行之后,exports不再指向module.exports。如果你难以区分清楚,一般最好就别用exports,只使用module.exports就行。

怎么区分模块是直接执行,还是被调用执行。

require.mainAPI就有这样的作用,如果模块是直接执行,那么这时require.main属性就指向模块本身。例如下面:

require.main === module
复制代码

为什么客户端不使用commonjs规范?

我们知道客户端(浏览器)加载资源主要是通过网络获取,一般本地读取的比较少,而node.js主要是用于服务器编程,模块文件一般都存在于本地硬盘上,然后I/O读取是非常快速的,所以即使是 同步加载 也是能够适用的,而浏览器加载资源必须通过异步获取,比如常见的ajax请求,这时候AMD规范就非常合适了,可以异步加载模块,允许回调函数。

客户端的规范不仅仅只有AMD,还有CMD.

每个规范的兴起背后总有一些原因,requirejs的流行是因为commonjs未能满足我们需要的效果,sea.js被创造的 原因 也是因为requirejs不能满足一些场景。

AMD和CMD的区别

- AMD CMD
原理 define(id ?,dependencies ?,factory)定义了一个单独的函数“define”。id为要定义的模块。依赖通过dependencies传入factory是一个工厂参数的对象,指定模块的导出值。 CMD规范与AMD类似,并尽量保持简单,但是更多的与common.js保持兼容性。
优点 特别适用于浏览器环境的异步加载 ,且可以并行加载。依赖前置,提前执行。 定义模块时就能清楚的声明所要依赖的模块 依赖就近,延迟执行。 按需加载,需要用到时再require
缺点 开发成本较高,模块定义方式的语义交为难理解,不是很符合通过的模块化思维方式。 依赖SPM打包,模块的加载主观逻辑交重。
体现 require.js sea.js

ES6让前端模块化触手可及

概念

ES6的模块不是对象,import语法会被JavaScript引擎 静态分析 ,请注意,这是一个很重要的功能,我们通常使用commonjs时,代码都是在运行时加载的,而es6是在编译时就引入模块代码,当然我们现在的浏览器还没有这么强大的功能,需要借助各类的编译工具(webpack)才能正确的姿势来使用es6的模块化的功能。也正因为能够编译时就引入模块代码,所以使得静态分析就能够实现了。

ES6模块化有哪些优点

  • 静态化编译 如果能够静态化,编译的时候就能确定模块的依赖关系,以及输出和输入的变量,然后CommonJS和AMD以及CMD都只能在运行代码时才能确定这些关系。

  • 不需要特殊的UMD模块化格式 不再需要UMD模块的格式,将来服务器和浏览器都会支持ES6模块格式。目前各种 工具 库(webpack)其实已经做到这一点了。

  • 目前的各类全局变量都可以模块化 比如navigator现在是全局变量,以后就可以模块化加载。这样就不再需要对象作为命名空间。

需要注意的地方

  • export语句输出的接口,通过import引入之后,与其对应的值是动态的绑定关系,也就是模块的内的值即使改变了,也是可以取到实时的值的。而commonJS模块输出的是值的缓存,不存在动态更新。
  • 由于es6设计初衷就是要静态优化,所以export命令不能处于 块级作用域内 ,如果出现就会报错,所以一般export统一写在底部或则顶层。
function fun(){
  export default 'hello' //SyntaxError
}
复制代码
  • import命令具有提升效果,会提升到整个模块的头部首先执行。例如:
fun()
import {fun} from 'myModule';
复制代码

上面的代码import的执行早于fun调用,原因是import命令是编译阶段执行的,也就是在代码运行之前。

export default使用

export default就是输出一个叫default的变量或方法,然后系统允许你为它取任意名字。所以,你可以看到下面的写法。

//modules.js
function add(x,y){
  return x*y
}
export {add as default};
//等同于
export default add;

//app.js
import {default add foo} from 'modules';
//等同于
import foo from 'modules'
复制代码

这是因为export default命令其实只是输出一个叫做default的变量,所以它后面不能跟变量声明语句。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Spring揭秘

Spring揭秘

王福强 / 人民邮电出版社 / 2009.8 / 99.00元

没有教程似的训导,更多的是说故事般的娓娓道来,本书是作者在多年的工作中积累的第一手Spring框架使用经验的总结,深入剖析了Spring框架各个模块的功能、出现的背景、设计理念和设计原理,揭开了Spring框架的神秘面纱,使你“知其然,更知其所以然”。每部分的扩展篇帮助读者活学活用Spring框架的方方面面,同时可以触类旁通,衍生出新的思路和解决方案。 本书内容全面,论述深刻入理,必将成为每......一起来看看 《Spring揭秘》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换