J历史

  我们都知道,js在刚被创建的时候,只是为了在网页上写一些小脚本而已,比如网页特效,表单验证等等,创立者也许没觉悟到以后的js会发展到如此规模。这是web1.0时代。

  在web 2.0时代,各种前端库,前端框架被开发出来,jquery,angular就是代表。此时js的功能也就从写写小特效啥的跃迁到了应用开发的级别上。可以说,js经历了工具类库,组件库,前端框架,前端应用的变迁。

  于是在越来越广泛的应用中,js暴露了它先天就缺乏的一项功能:模块。在其它高级语言,都有模块的定义,java有类,python有import机制,ruby有require,php有require和include。而js此时还单纯的用script标签引入,用命名空间来约束代码,杂乱无章,于是,commonjs规范便应运而出。

  commonJS的模块规范

  commonjs规范的出发点就是让js在任何地方都能运行。它弥补了js此时的几点缺陷:

  没有模块概念

  标准库较少

  没有标准接口

  没有包管理系统

  当然,如今commonjs规范已经解决了大部分问题,而且涵盖了模块,二进制,Buffer,字符集编码,I/O流,单元测试,web服务网关接口,包管理,等。

  commonjs对模块的定义很简单,包含了模块定义,模块引用,模块标识3个部分。

  模块引用

  var xx = require('xxx')

  关键字require来接受模块标识,引入这个模块的API到上下文中。

  模块定义

  一个例子来解释:

  //add.jsfunction add(a,b){ return a+b;

  }// 这样导出的 add是作为 exports 的一个方法被导出的exports.add = add;// main.jsvar Add = require('add');console.log(Add.add(1,2));//Add是require引入的模块名,add是方法名。

  node在编译的时候,会把代码封装成如下的样子

  // require 是对 Node.js 实现查找模块的 Module._load 实例的引用// __finename 和 __dirname 是 Node.js 在查找该模块后找到的模块名称和模块绝对路径(function(exports,require,module,__filename,__dirname){ function add (a,b){ return a+b;

  }

  exports.add = add;

  })

  为了将函数直接导出成一个模块,而不是一个方法,用到了全局变量module,下面就是我们常见的样子了:

  // add.jsfunction add (a,b){ return a+b ;

  }module.exports = add;// main.jsvar add = require('add');console.log(add(1,2));

  模块标识

  模块标识就是require()里的参数,必须是小驼峰命名的字符串,或者是路径(./ 或../)。可以没有后缀.js

  Node的模块机制

  Node并不是完全按照commonjs规范来实现,而是进行了一些取舍,并增加了自己的一些特性。

  Node中引入模块,经历3个步骤:

  路径分析

  文件定位

  编译执行

  Node中模块分为2种,核心模块(Node提供的)和文件模块(用户自己编写的)

  Node对引入过的模块会进行缓存,就像前端浏览器会缓存静态脚本来提高性能一样。require()方法在对同一模块的二次加载一律采用缓存优先的方式。但是对核心模块的缓存检查优先于对文件模块的缓存检查。

  路径分析

  就是对模块标识的分析呗。

  模块标识符在Node中分以下几类:

  核心模块,如http,path

  ./ ../相对路径

  / 绝对路径

  非路径形式的文件模块。

  文件分析

  如果模块标识符没有后缀,默认补上后缀从.js,.json,.node来次序查找。

  模块编译

  js编译上面已经提到了。Node对JS文件进行了包装,在头部添加了(function (exports, require, module, __filename, __dirname) {...})。这样每个模块都进行了作用域隔离。包装之后通过vm原生模块的runInThisContext()方法执行(类似eval,只是具有明确上下文,不污染全局)返回一个function。然后将上述参数传给这个function执行。

  json编译更简单,Node直接用JSON.parse()方法编译json内容,得到的对象赋给exports。

  包和NPM

  commonjs的包规范包含2个组成部分,包结构和包描述文件

  包描述文件:package.json

  包结构:

  package.json 包描述文件

  bin: 存放可执行二进制文件的目录

  lib 存放js代码的目录

  doc. 存放文档的目录

  test: 存放单元测试用例的代码

  NPM的用法就不多说了。

  前后端公用模块

  自从Node出来以后,js也可以运用在后端。但是前后端的JS扮演的角色不同,浏览器端的js需要经历从同一个服务器分发到多个客户端执行。服务端的js则是相同的代码多次执行。前者的瓶颈在于带宽。后者的瓶颈在于CUP和内存。前者需要通过网络加载。后者从磁盘中加载。

  因为Node基于commonjs规范来同步的加载模块的。前端若用同步方式来加载模块,在用户体验上会造成很大的问题。UI在初始化的时候需要等待很长时间来加载js脚本。所以提出了异步模块定义AMD和CMD。这在我的另一篇博客中有提到。就不多说了。

  为了写个能兼容前后端的模块规范,类库的开发者要把代码包装在一个 闭包里。这样就能兼容Node,AMD,CMD和常见的浏览器。

浅谈NodeJs的模块机制的更多相关文章

  1. 浅谈Python时间模块

    浅谈Python时间模块 今天简单总结了一下Python处理时间和日期方面的模块,主要就是datetime.time.calendar三个模块的使用.希望这篇文章对于学习Python的朋友们有所帮助 ...

  2. 浅谈Java的反射机制和作用

    浅谈Java的反射机制和作用 作者:Java大师 欢迎转载,转载请注明出处 很多刚学Java反射的同学可能对反射技术一头雾水,为什么要学习反射,学习反射有什么作用,不用反射,通过new也能创建用户对象 ...

  3. 浅谈:Redis持久化机制(一)RDB篇

    浅谈:Redis持久化机制(一)RDB篇 ​ 众所周知,redis是一款性能极高,基于内存的键值对NoSql数据库,官方显示,它的读效率可达到11万次每秒,写效率能达到8万次每秒,因为它基于内存以及存 ...

  4. 浅谈:Redis持久化机制(二)AOF篇

    浅谈:Redis持久化机制(二)AOF篇 ​ 上一篇我们提及到了redis的默认持久化方式RDB,是一种通过存储快照数据方式持久化的机制,它在宕机后会丢失掉最后一次更新RDB文件后的数据,这也是由于它 ...

  5. 浅谈C语言中断处理机制

    一.中断机制 1.实现中断响应和中断返回 当CPU收到中断请求后,能根据具体情况决定是否响应中断,如果CPU没有更急.更重要的工作,则在执行完当前指令后响应这一中断请求.CPU中断响应过程如下:首先, ...

  6. 浅谈 ArrayList 及其扩容机制

    浅谈ArrayList ArrayList类又称动态数组,同时实现了Collection和List接口,其内部数据结构由数组实现,因此可对容器内元素实现快速随机访问.但因为ArrayList中插入或删 ...

  7. 60.浅谈nodejs中的Crypto模块

    转自:https://www.cnblogs.com/c-and-unity/articles/4552059.html node.js的crypto在0.8版本并没有改版多少,这个模块的主要功能是加 ...

  8. 浅谈nodejs中HTTP模块应用

    这里给大家分享下后端人员如果利用nodejs对数据的一些处理情况  适用于初学者使用 大牛勿喷 给大家分享下主要后端思想部分代码,前端部分就不展示了 const http = require(&quo ...

  9. 浅谈Nodejs应用的主文件index.js的组成部分

    前言 Node妹子的问世,着实让我们前端攻城狮兴奋了一把,尤其本屌听说Javascript可以写服务端后,兴奋的像是看到了二次元萝莉的胖子...(●'◡'●).呃哼...YY先到这里,原谅本屌是个二次 ...

随机推荐

  1. 目标检测-Faster R-CNN

    [目标检测]Faster RCNN算法详解 Ren, Shaoqing, et al. “Faster R-CNN: Towards real-time object detection with r ...

  2. 图文讲解zabbix安装全过程(5)

    在了解<zabbix硬件.软件需求>之后,在你心里应该有备选的机器.今天开始安装zabbix.zabbix需要LNMP或者LAMP环境.环境的搭建不在本章范围内. LNMP环境配置Linu ...

  3. python学习笔记(六)time、datetime、hashlib模块

    一.hashlib模块 python中的hashlib模块用来进行hash或者md5加密,而且这种加密是不可逆的,所以这种算法又被称为摘要算法.在python3的版本里,代替了md5和sha模块,主要 ...

  4. ORACLE USERENV函数

    ORACLE USERENV函数 USERENV返回关于当前会话的信息.此信息可以用于编写一个应用程序特定的审计跟踪表或确定特定于语言的角色目前使用的会话. 参数 功能 CLINET_INFO 返回最 ...

  5. [golang note] 数组切片

    数组 √ golang数组包含的每个数据称为数组元素(element),数组包含的元素个数被称为数组长度(length). √ golang数组的长度在定义后不可更改,并且在声明时可以是一个常量或常量 ...

  6. C++ error C2064:

    error C2064: term does not evaluate to a function 错误原因,非函数,当成函数使用了

  7. 搜狗员工用百度算什么,谷歌员工当着老板的面用bing,结果悲剧了!

    之前看到一篇文章,写的是搜狗的员工遇到问题时,用百度,结果网友的评论真是亮瞎眼.今天,W3Cschool小师妹将为大家分享一个类似的故事,那就是谷歌员工当着老板的面,竟然用BING. 这位谷歌员工称, ...

  8. 2.MySQL简介

    MySQL是一种DBMS,即它是一种数据库软件.   1.连接   为了连接到MyAQL,需要一下信息: ➡️主机名(计算机名)---如果连接到本地MySQL服务器,为localhost ➡️duan ...

  9. Mac Outlook邮箱MicrosoftExchange邮箱快满了,请减小邮箱大小。

    这两天我的Mac电脑中的Exchange总是收到公司的邮箱发来的[存储空间不足的告警邮件] MicrosoftExchange329e71ec88ae4615bbc36ab6ce41109e@your ...

  10. hdu2328 Corporate Identity

    地址:http://acm.hdu.edu.cn/showproblem.php?pid=2328 题目: Corporate Identity Time Limit: 9000/3000 MS (J ...