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. ubuntu下30天自制os 的学习计划

    30天自制os的学习也告一段落,由于有其他更重要的事情要集中精力去处理.书本从15天開始就是多任务了.可是不得不停下一阵子. 以下总结下学习中遇到的一些问题. 1:学习这前14天中.问题最大的是关于G ...

  2. 004-hadoop家族概述

    hadoop家族 名称 简介   Hadoop 分布式基础架构 Hadoop的框架最核心的设计就是:HDFS和MapReduce.HDFS为海量的数据提供了存储,则MapReduce为海量的数据提供了 ...

  3. PHP魔术方法和魔术常量介绍及使用

    魔术方法(Magic methods) PHP中把以两个下划线__开头的方法称为魔术方法,这些方法在PHP中充当了举足轻重的作用. 魔术方法包括: __construct(),类的构造函数 __des ...

  4. dijstra算法,求源点到各个顶点的最短距离

    1:dijstra算法常用语求最短距离, dijstra每次从未发现节点n[]中,发现距离源点最短的节点m,求出最短节点后,将m添加到已发现节点y[]中,用该节点m进行更新其它未发现节点n[]-m的最 ...

  5. 工作中发现Web服务器的磁盘满后故障分析

    遇到的问题:   今天收到报警,某台线上的服务器的磁盘已满,但是登上去使用du -sh /log/* 检查, 发现文件的大小远远小于磁盘的空间,此时不知道该如何解决! 解决的方法:   其实,如果只是 ...

  6. Code signing is required for product type 'Application' in SDK 'iOS 11.2'

    在打包的时候出现这样一个错误,Code signing is required for product type 'Application' in SDK 'iOS 11.2'  ,就是说代码签名证书 ...

  7. JavaScript:学习笔记(9)——Promise对象

    JavaScript:学习笔记(9)——Promise对象 引入Promise Primose是异步编程的一种解决方案,比传统的解决方案回调函数和事件更加合理和强大.如下面为基于回调函数的Ajax操作 ...

  8. XDU 1056

    解法一:简单搜索肯定TLE,只是单纯的想写一发搜索练练手 #include<cstdio> #include<cstring> #define maxn 1005 using ...

  9. ruby中的self

    self,自己,在ruby中表示当前对象或默认对象.程序执行的任一时刻,有且仅有一个self. 1.谁成为self,在什么位置成为self? 要知道哪个对象是self,就必须知道当前的上下文.上下文主 ...

  10. hihocoder1479 三等分

    地址:http://hihocoder.com/problemset/problem/1479 题目: 三等分 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi最近 ...