您的位置:首页 > Web前端 > Node.js

nodeJS入门——node介绍&模块

2017-11-06 16:02 337 查看

1、什么是 Node

官网:https://nodejs.org/en/

      Node 不是一种新的语言

      Node 是一个可以用来解析和执行 JavaScript 语言的一个环境或者说是一个平台

      Node 环境或者说平台 给 JavaScript 语言,提高了 一些 例如文件操作、网络操作等接口API

Node 的特点:事件驱动、  异步IO模型 、 跨平台

官方解释:

  Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. 

   Node.js 是一个构建与 Chrome 的 V8 JavaScript 引擎之上的一个 JavaScript 运行时环境

   Node 可以用来解析和执行 JavaScript 代码

   Node 无法解析 DOM 和 BOM 等对象

   Node 只关心数据部分,例如 读写文件,提供 Web 服务

  

  Node.js uses an event driven, non blocking I/O model that makes it lightweight and efficient. 

   Node.js 使用 事件驱动和非阻塞IO模型,使它非常的轻量和高效

   event driven:事件驱动

   non blocking I/O model:非阻塞IO模型

 

 Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world.

   Node.js 的包管理系统 npm 是世界上最大的开源库生态系统

  Node 的诞生历程

   Node 的作者:Ryan Dahl

   2004年还在纽约读数学系博士

   2006年退学(世界那么大,我想去看看),生活所迫,选择了码农

   接项目、工作、旅行,两年之后,成为了高性能Web服务器的专家

   2009年5月,Ryan Dahl 在 github 上发布了最初的 Node 版本

   2010年底,Ryan Dahl 加入 Joyent 公司全职负责 Node 的发展

   2011年7月,Node 在微软的支持下发布了 Windows 版

   2012年1月底,Ryan Dahl 将掌门人身份转交给了 Isaac Z.Schlueter,自己转向一些研究项目

   2014年12月,多为重量级Node开发者不满 Joyent 对 Node 的管理,自立门户创建了 `io.js`

   2015年9月,Node 与 io.js 合并,Node 的版本从 0.12.7 直接升级到了 4.0.0

   合并后的 io.js 和 Node 在 Joyent 公司的维护下并行了两个版本:

     一个是4.x.x  还是原来的 Node,这个版本是稳定版

     一个是5.x.x,目前已经更新到了 6.4.0,其实就是 io,最新特性版,不建议生产环境使用

  为什么要学习 Node

   Node 打破了过去 JavaScript 只能在浏览器中运行的局面

   前后端编程环境统一,大大降低了前后端语言切换的代价

   全栈开发工程师

     后端开发工程师

     前端开发工程师

     移动端开发工程师

   前端  后端

  使用 Node 可以做什么

   高性能的网站服务器

   实时多人游戏后台服务器

   简单易用的命名行应用程序

     gulp、less

   高大上的桌面应用程序

     使用 Web 技术 作为解决方案

   底层的物联网开发

   移动开发

     Ionic 安卓 IOS

     使用 Web 技术作为解决方案

 CommonJS 规范

nodeJS遵守的规范

  一个单独的文件就是一个模块

 
4000
每一个模块都是一个单独的作用域

  每个文件对外接口是 `module.exports` 对象

    还有一个别名 `exports` 指向了 `module.exports` 接口对象

  `require` 方法用于加载模块,得到模块的 `module.exports` 接口对象

Node 根据 `CommonJS` 规范实现了自己的一套模块系统。



核心模块和文件模块

在 Node 中,模块分为两类,一类是 Node 提供的模块,称为核心模块。另一类是用户编写的模块,称为文件模块。

核心模块在 Node 源代码的编译过程中,编译进了二进制执行文件,

在使用的时候,`require` 参数中直接写核心模块名即可。

例如:`var fs = require('fs')` ,表示加载用于文件操作的 `fs` 核心模块。

在Node中,文件模块则是在运行时动态加载,完全以同步的方式加载,然后执行。

浏览器中的模块必须通过网络去加载,所以无论是 SeaJS 还是 RequireJS 都是预先加载所有的模块。

在 Node 中,因为 JavaScript 模块运行在服务器端,加载模块代码的时候可以直接通过本地就可以加载了,

所以,Node 中加载模块都是同步的方式进行加载的,加载到哪里就执行到哪里。



 模块加载过程机制

  优先从缓存加载

  路径分析和文件定位

    模块标识符分析

      核心模块

      路径形式的文件模块

      自定义模块
    

无论是核心模块还是文件模块都是通过 requrie 方法进行加载

  1、 优先从缓存中加载(node对于已经加载过的模块会缓存起来,下次如果继续使用,直接从缓存中拿),无论是核心模块还是文件模块

  

  2.1 、如果模块标识是核心模块,那么 node 去读取自己的核心模块

  2.2 、如果模块标识是以 . 开头的模块,那么这个模块就是一个相对路径文件模块。

  2.3、 既不是路径形式的文件模块,也不是核心模块,是一个包

 

  3.1 、node 先在当前目录下找有没有一个叫做 node_modules 的目录, 如果找到,则找里面有没有对应的包名

  3.2、 如果找到该包名对应的目录,找里面的 package.json 文件

  3.3 、如果找到 package.json 文件,那么找里面的 main 属性,如果找到 main 属性,直接加载该属性对应的 模块文件

  3.4 、如果没有找到 package.json 文件 或者 package.json 文件中没有 main 属性 或者 main 指定的入口文件模块不存在,查找失败

  

 4、 node 自动进入上一级目录 重复上面的步骤

  node 中的包模块查找机制非常类似于 JavaScript 中的 作用域链 和 原型链

  

 5、 如果直到 当前文件模块所属的盘符根路径还找不到,最后报错。

文件定位

      文件扩展名分析:按照 `.js` `.json` `.node` 的次序补足扩展名

      目录分析和包

   

模块编译

      `.js` 文件,通过 fs 模块同步读取文件后编译执行

      `.node` 文件

      `.json` 文件,通过 fs 模块同步读取文件后使用 `JSON.parse()` 解析返回结果

      其它扩展名,被当作 `.js` 文件载入

兼容模块规范

在代码中加入这些判断

<!-- 兼容CommonJS和 window  -->
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = _;
}
exports._ = _;
} else {
// 向 Window 暴露接口对象
root._ = _;
}


兼容AMD模块规范

// 判断在全局是否有 define 这个方法,同步 define 有一个属性叫做 amd
// 两个判定条件都成功,就意味着当前浏览器环境引入了 require.js 文件
if (typeof define === 'function' && define.amd) {
define('underscore', [], function() {
return _;
});
}


兼容CMD规范

if (typeof define === 'function' && define.cmd) {
define(function (require, exports, module) {
module.exports = _;
});
}


node对象

3、Node 中的 JavaScript

     REPL
(Read Eval Print Loop:交互式解释器) 运行环境 :
 可以执行一些js代码

     ECMAScript

nodeJS对象

全局对象

  global :  相当于浏览器中的window,不建议使用容易造成冲突

  Console : 和浏览器中的console功能相同,(火狐浏览器给JS加的,用于调试,不在规范中)

  process : 进程对象, 获取系统相关的信息

  Buffer(class): 全局构造函数,用来操作二进制数据

全局函数

  setInterval 和 clearInterval

  setTimeout 和 clearTimeout

  setImmediate 和 clearImmediate

模块内成员

  变量:

__dirnam :获取当前文件局对路径(不包括文件名)

__filename: 获取当前文件的绝对路径(包括文件名)

方法:

  require ('路径') :  获取模块的方法
  exports:

  exports= module.exports

exports是引用 module.exports的值,而模块导出的时候,真正导出的执行是module.exports,而不是exports

module.exports和exports的区别就是var a={}; var b=a; 中a和的区别。exports指向的只是一个引用。改变exports的指向后所添加的exports.***都是无效的。因为require返回的只是module.exports.   所以不能在使用了exports.***之后,改变module.exports的指向。因为exports.***添加的属性和方法并不存在与module.exports所指向的新对象中。

     个人建议,可以全部使用module.exports来应对所有的情况,并尽量减少犯错的机会。

  

module

module对象

 Node内部提供一个Module构造函数,所有模块都是Module的实 例 • 每个模块内部,都有一个module对象,代表当前模块。 

     – module.id 带有绝对路径的模块文件名 

     – module.filename      模块的文件名,带有绝对路径

     – module.loaded 表示模块是否已经完成加载 

     – module.parent 返回一个对象,表示调用该模块的模块。

     – module.children      返回一个数组,表示该模块要用到的其 他模块。

     – module.exports 模块对外输出的值(暴露模块方法和属性)

 module.exports属性表示当前模块对外输出的接口, 其它文件加载该模块,实际上就是读取 module.exports属性 • 点儿导出单个函数、对象或者值的时候非常有用

为了方便,Node为每个模块提供一个exports变量, 指向module.exports。 相当于在每个模块头部,有这样一行命令: var exports = module.exports; 

结果就是: – 在对外输出模块接口时,可以向exports对象添加方法 

及可以直接使用exports代替module.exports

注意:不能直接给exports赋值,因为这样等于切断了 exports和module.exports的联系

模块加载

require()加载模块
• 在Node.js中,require命令用于加载模块文件
• 基本功能: 1、读取并执行一个JavaScript文件  2、 然后返回该模块的exports对象  3、 如果没有发现指定模块,会报错

require模块加载规则:

     • 参数字符串以 “/”开头 (绝对路径)

     • 参数字符换以“./”开头 (相对路径)

     • 参数字符串没有路径,表示加载核心模块, 或者一个位于各级node_modules目录已安装的模块 

     • 参数字符串可以省略后缀名 : .js、.json、.node 

        – .js会当做JavaScript脚本文件解析

        – .json会以JSON格式解析 

        – .node会以编译后的二进制文件解析 

注意: node项目目录结构没有要求, 相对路径是相对于node命令所在的目录

核心模块与文件模块

     • 核心模块 :require(‘核心模块名’) 

     • 文件模块 : require(‘路径+模块名’)路径包括相对路径与绝对路径 ,绝对路径的加载速度快

 总结 

     – 加载模块时将运行模块文件中的每一行代码 

     – 相同模块多次引用不会引起模块内代码多次执行 

核心模块:

      http : 提供http服务器功能

      url :解析url

      fs :与文件系统交互

      querystring :解析url查询字符串

      util :提供一系列实用小工具

      path : 处理文件路径

      核心模块的源码都在node的lib子目录中。为了提高运行效率,她们安装的时候都会被编译成二进制文件

模块的加载机制:

  如果require绝对路径的文件,查找时不会去遍历每一个node_modules目录,其速度最快。 其余流程如下: 
1. 从module path数组中取出第一个目录作为查找基准。 
2. 直接从目录中查找该文件,如果存在,则结束查找。如果不存在,则进行下一条查找。 
3. 尝试添加.js、.json、.node后缀后查找,如果存在文件,则结束查找。如果不存在, 则进行下一条。 
4. 尝试将require的参数作为一个包来进行查找,读取目录下的package.json文件,取得 main参数指定的文件。 
5. 尝试查找该文件,如果存在,则结束查找。如果不存在,则进行第3条查找。 
6. 如果继续失败,则取出module path数组中的下一个目录作为基准查找,循环第1至5个 步骤。 
7. 如果继续失败,循环第1至6个步骤,直到module path中的最后一个值。 
8. 如果仍然失败,则抛出异常。
总结
所有代码都运行在模块作用域,不会污染全局作用域 
模块可以多次加载,但是只会在第一次加载的时候运行 一次,然后运行结果就被缓存了,以后再加载,就直接 读取缓存结果 
模块的加载顺序,按照代码的出现的顺序是同步加载的 
require是同步加载模块的




 路径操作模块:`path`

`path` 是一个核心模块,在使用的时候必须加载。

  basename(p[,ext]) 注意第二个参数用法  获取文件名

  dirname(p)  获取文件目录

  extname(p)  获取文件扩展名

  isAbsolute(path)  判断是否是绝对路径

  join([path1][,path2][,...]) 拼接路径字符串

  sep 获取操作系统的文件路径分隔符

 文件操作模块:‘fs’

`fs` 是一个核心模块,在使用的时候必须加载。

     同步和异步文件系统调用

异步:

fs.readFile('./README.md', function (err, data) {
if (err) {
throw err
}
console.log(data.toString())
})


   err 就表示操作的过程中可能出错的对象

   data 就是最终的执行结果

  IO 需要时间,例如有 1MB 的文件 和 100MB 的文件

  异步IO 不会阻塞后续代码的继续执行

  一般一个异步IO往往都需要一个回调函数来接收处理结果

  而 回调函数中一般第一个参数都是 err 对象,表示可能出错的对象

  第二个参数才是真正的数据

异步捕获不了异常,处理异步代码中的异常

  异步IO,如果出错,node 不会帮你自动抛出异常

  对于异步IO,try-catch 是无法捕获异常的

  如果想要捕获异常,只能通过回调函数中的参数 err 来判断进行捕获

  所以 err 一定要进行判断,否则代码不健壮

同步:

try {
var data = fs.readFileSync('./aaa').toString().
console.log(data)
} catch (e) {
return console.log('读取文件失败了')
}


  同步IO,执行同步IO,当前代码阻塞,等待IO数据的返回

  使用同步IO符合代码编程人员的思维习惯,但是性能不高,必须干完一件事儿,才能继续下一件事儿

  对于同步IO,只能使用 try-catch 来捕获异常

fs模块对文件的几乎所有操作都有同步和异步两种形式:

例如:`readFileSync()` 和 `readFile()`

    8.2 文件基本操作

     8.2.1 文件写入

     8.2.2 向文件中追加内容

     8.2.3 文件读取

     8.2.4 其它文件操作任务

     8.2.  文件监视

    8.3 目录操作

    8.4 流

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: