Node的学习
Node.js 是一个基于 Google 所开发的浏览器 Chrome V8 引擎的 JavaScript 运行环境。
属于 服务端的 JavaScript 。
2019.03.01 JavaScript 的进阶学习 (Node.js)_01
- Node 的特点
作为后端的JavaScript 的运行平台,Node 保留了前端浏览器 JavaScript 中那些熟悉的接口,没有改写语言本身的任何特性,依旧基于作用域和原型链,区别在于它将前端中广泛运用的思想迁移到了服务器端。 - 学习 Node 的目的
全栈工程师(Full Stack Engineer),即包括用户界面,业务逻辑,数据建模,服务器,网络与环境等。Node.js 的出现,使 JavaScript 语言既可以进行客户端的开发(页面交互),又可以进行服务器端的开发(数据交互),还可以与数据库交互。大大减少了学习的成本。
本文是在学习 《Node.js 开发实战详解》清华大学出版社,可以在官网查询教程和源码
视频教程
源码地址
JavaScript 温故
文章目录
一、模块机制
- JavaScript 从一方面说,先天缺乏功能:模块。
其他高级语言中,Java 有类文件,Python 有 import 机制,Ruby 有 require ,PHP 有include和require。而 JavaScript 中的<script>标签引入代码的方式显得杂乱无章,约束能力差。
3.模块分为两类:原生模块和文件模块。原生模块即 Node.js API 提供的原生模块,原生模块在启动的时候加载。文件模块为动态加载模块,主要由 原生模块 module 来实现和完成。
- 原生模块的调用。
- 应用 Node.js 提供的 API require 来加载相应的 Node.js 模块,架子啊成功后返回一个 Node.js 模块对象。
var httpModule = require('http'); // 请求 http 模块
- 该模块中有 createServer、require 和 get 等多个方法和属性。
调用 HTTP 模块中的 createServer 、listen 方法来创建简单对象。
httpModule.createServer(function(res,req){}).listen(port,127.0.0.1);
- 文件模块的调用。
- 文件模块的指定引入必须是 文件路径,否则会报错 “can not find XX module”
/ 单斜杠 表示的是绝对路径 , ./ 点斜杠 表示的是 相对路径。
- 文件模块中,只有 exports 和 module.exports 对象暴露给外部的属性和方法,才能通过require返回的对象进行调用。
- Common JS 规范
Common JS 规范为 JavaScript 制定了一个美好的愿景,希望 JavaScript 能够在任何地方运行。
- 学习使用 Common JS 模块规范
Common JS 对模板的定义十分简单,主要分为 模块引用、模块定义和模块标识三部分
- 模块引用,require() ,这个方法是接受模块标识,引入一个模块的 API 到上下文当中。
var math = require('math');
- 模块定义,上下文提供了 exports 对象用于导出当前模块的方法或者变量,并且它是唯一导出的出口。
// math.js
exports.add = function(){
var sum=0,i=0,args=arguments,l=args.length;
while(i<l){
sum += args[i++];
}
return sum;
};
// program.js
var math = require('math');
exports.increment = function(val){
return math.add(val,1);
}
- 模块标识,传递给 require() 方法的参数,
必须是符合小驼峰命名的字符串,或者是.、..开头的相对路径,或者绝对路径。可以没有文件的后缀名 .js 。
模块化是一种设计思想,利用模块化可以把一个非常复杂的系统结构细化到具体的功能点,每个功能点看做一个模块,然后通过某种规则把这些小的模块组合到一起。Node.js 是一个高度模块化的平台。
什么是模块化 。
模块化是指解决一个复杂问题时自顶向下逐层把系统划分成若干模块的过程,有多种属性,分别反映其内部特性。- 简述模块化开发的优势 。
模块化开发主要有两种方式:
1. 依赖加载。通过相关require api加载,当加载完成之后再运行逻辑代码。2. 依赖打包。经典代表就是webpack,其实就是写代码的时候分开模块,但打包的时候按依赖关系找到各个模块,最后打包到同一个文件上,并给每个chunk标识id,运行逻辑代码时将模块引用指向该id,从而实现模块化。
传统的开发方式是在页面上通过脚本标签引入,等所有脚本资源加载完成后再运行逻辑代码。
综上所述:
1、除了模块化支持的脚本必须加载进来以外,其他脚本都可以异步请求,可以加速渲染出页面,
2、require.js,sea.js等也会做好加载重试和模块缓存的处理,确保所有模块运行良好。
3、模块内的名字和外界不会冲突。模块内命名冲突,则是模块颗粒不够小,还可以继续分割出模块。
4、代码重用。模块化都有缓存机制,在二次调用时无需再解析,直接获取到缓存模块内容。
Node.js 实现 Web 解析 DNS
- 1、创建 js 文件,加载需要的 Node.js 原生模块。
/* 首先 require 加载需要的 Node.js 原生模块。 */
var http = require('http'); // 服务器模块
dns = require('dns'); // DNS 查询
fs = require('fs'); // 文件操作
url = require('url'); // url 处理
querystring = require('querystring'); // 字符串处理
不建议在一个文件夹中多次 require 同一个对象。
http.createServer(function(req,res){
// 写 http head 返回 html ,因此 Content-Type 为 html
res.writeHead(200,{'Content-Type':'text/html'}); // 添加响应头。
// 获取当前的 index.html 路径。
var realPath = _dirname + '/'+url.parse('index.html').pathname; // 获取 html 文件路径。
// 读文件
var indexPage = fs.readFileSync(realPath);
// 执行 http 响应返回到 Web 客户端。
res.end(indexPage);
}).listen('3000','127.0.0.1');
console.log('Server is starter in 127.0.0.1:3000');
- 2、新增请求的路由。
http.cteateServer 回调函数中的两个参数,res 处理 HTTP 的响应事件,req 处理HTTP 的请求事件。
在原有代码中的 http.cteateServer 回调函数中添加一个路由处理方法
http.createServer(function(req,res){
req.setEncoding("utf8");
var pathname=url.parse(req.url).pathname;
res.writeHead(200,{'Content-Type':'text/html'}); // 添加响应头。
router(res,req,pathname)。
}).listen('3000','127.0.0.1');
console.log('Server is starter in 127.0.0.1:3000');
function router(req,res,pathname){
switch(pathname){
case "/parse":
parseDns(req,res);
break;
default:
goIndex(req,res);
}
}
function goIndex(res,req){
// 获取 html 文件路径。
var readPath = _dirname + '/'+url.parse('index.html').pathname; // 获取 html 文件路径。
// 同步读取 index.html 文件的信息
var indexPage = fs.readFileSync(readPath); // 读取 index.html
// 返回
res.end(indexPage); // 通过 res 响应 html 数据到客户端。
}
function parseDns(res,req){
var postData = "";
req.addListener("data",function(postDataChunk){ // 数据传递时触发的事件函数,读取客户端传来的数据
postData += psotDataChunk;
});
// http 响应 HTML 页面。
req.addListener("end",function(){ // 数据接收完成,end 事件被触发后,执行DNS 域名解析。
var retData = getDns(postData,function(domain,addresses){ // 异步解析域名
res.writeHead(200,{'Content-Type':'text/html'});
res.end("<html><head><meta http-equiv='content-type' content='text/html;charset=utf-8' ></head><div style='text-align:center'>Domain:<span style='color:red'>"+domain+"</span>IP:<span style='color:red'>"+addresses.join(',')+"</span></div></html>);
});
return;
})
}
// 异步回调函数,回调执行数据返回客户端,根据 domain 和 address 参数
function getDns(postData,callback){
var domain = querystring.parse(postData).search_dns;
/* 异步解析域名 */
dns.resolve(domain,function(err,addresses){
if(!addresses){
addresses = ['不存在域名']
}
callback(domain,addresses);
});
}
Node.js 重构 DNS 解析网站
- index.js
- router.js
- parse_dns.js
- main_index.js
- 上述代码执行编写完之后还需要加上 之前编写好的 index.html 页面编辑运行。
原生模块 与 文件模块可以执行同一事件。
- 通过 原生模块 和 文件模块 都可以执行东阳的操作 (读取 index.html 返回给客户端,并执行跳转界面),
1.为什么还需要文件模块来处理呢 ? (文件模块的好处优点)
文件模块可以实现模块化编程,便于项目的维护和开发。项目开发之前,必须要做系统的架构分析,将系统整个架构分析清晰后,对 Node.js 的模块进行模块化面向接口编程,
这样不仅利于团队的合作开发,同时在一定程度上海市提高代码的可维护性和扩展性。通过上面两种方法的应用实现,来突出显示 Node.js 中文件模块对代码设计的重要性。
exports 和 module.exports
exports 和 module.exports 的作用都是将文件模块和属性暴露给 require 返回的对象进行调用。二者之间存在本质区别,exports的属性和方法都可以被module.exports替代。但是 exports 不能代替 module.exports 的方法,可以理解为 包含关系。
- module.exports 方法还可以单独返回一个数据类型,而 exports只能返回的一个 Object 对象。当我们需要返回一个数组、字符串、数字等的类型时,就必须使用 module.exports。
### name.js
module.exports = ['hello','world'];
### show.js
msgArr = require('./name.js');
console.log(msgArr.join(' ')); // 利用数组的 join 方法,空格分割显示数组的每一项
### 执行结果
hello world
- 当使用了 module.exports 关键词后,该模块中的所有 exports 对象执行的属性和方法都将被忽略。
### ignore_exports.js
module.exports = 'hello world'; // module.exports 返回一个字符串
exports.name='robertChao'; // 使用 exports 返回一个对象
/* 定义showName 函数,并暴露给外部接口 */
exports.showName=function(){
console.log('My Name Is Funciton');
};
console.log(module.exports);
### ignore_exe.js
var Book = require('./ignore_exports.js');
console.log(Book);
console.log(Book.name);
console.log(Book.showName());
#### 得到结果
hello world
hello world
undefined
undefined
第一个 hello world 是在 ignore_exports.js 中打印 console.log(module.exports);,
第二个 hello world 是在 ignore_exe.js 中 console.log(Book); 打印显示的,
这也说明了,require 返回的数据对象 和 module.exports 对象是相同的。
undefined 是 console.log(Book.name);,require 无法获取,主要原因是在 exports 之前执行了 module.exports 方法,导致 exports 失效,同时 showName() 函数不存在是同样的原因。
安装 node.js
- 官网下载 :https://nodejs.org/
- 安装教程 :http://www.runoob.com/nodejs/nodejs-install-setup.html
安装完成之后呢,点击 finish出现。
按任意键后 弹出 Power Shell 。 - ** 测试是否安装成功了**
- 了解一些 CMD 命令 。
CMD 命令大全
常用的cmd命令:
1、dir
:查看当前目录下的所有条目。
2、cd
:切换目录。
3、cls | clear
:清屏。
4、cd..
:退回上一级。
5、cd \
:退回盘符的根目录。 - 新建一个 Web 项目。
- 下图光标一直闪烁
- 浏览器出现以下的内容,便是成功了。
二、Node.js 基础入门。
2.1 REPL 运行环境。
- 什么是 REPL 运行环境(可交互运行环境).
为了方便开发者测试 JavaScript 代码,Node.js 提供了REPL可交互运行环境。可以解析 JavaScript 代码,执行变量和函数的相关操作。打开终端(Dos窗口,cmd小黑窗),输入node,便进入 REPL 运行环境。
- Node.js 为 REPL 运行环境提供了一些常用命令。
2.1、Ctrl + C
:终止当前命令。
2.2、Ctrl + C + C
:终止 REPL 运行。
2.3、Ctrl + D
:终止 REPL 运行。
2.4、Up / Down
:查看 / 修改以前的命令。
2.5、Tab
:当前指令列表。
2.6、.help
:显示所有命令的列表。
2.7、.break
:退出多行表达式。
2.8、.clear
:从多行表达式中退出。
2.9、.save filename
:当前 Node REPL 会话保存到文件中。
2.10、load filename
:加载文件的内容在当前 Node REPL 会话中。
NPM 简介
NPM 是 Node Packaged Moduled,是 Node.js 的包管理器。开发者可以通过 NPM 提交个人 Node.js 模块成果,而其他人也可以使用 NPM下载这些 NPM 模块包,并将 NPM 模块应用到项目中。
- Windows 系统下使用 msi 为后缀名的 Node.js 安装文件安装后,会默认安装 NPM 模块。
- 安装完成之后,可以使用 npm -help 查看 NPM 的指令使用方法,
- 最常用的是 npm install 安装模块 和 npm uninstall 卸载模块。
- 会在 当前目录下新增一个 node_modules 文件夹,并会在 node_modules 文件夹中添加 NPM 模块。
Express 框架。
- Node.js 的项目模块 express 模块,
- scoket.js 模块,使用 scoket 协议处理长连接多请求的问题,
- forever 模块,来实现项目的运营、监控,
- jade 模块,处理 Node.js 无法内嵌 html 的问题,
- request 模块,解决 Node.js 发起 HTTP 请求处理模块,
- formidable 表单数据处理模块。
express 是一个 Node.js 的 Web 开源框架,该框架可以快速搭建 Web 项目开发的框架。主要集成了 Web 的 http 服务器的创建、静态文件管理、服务器 url 请求处理、get 和 post 请求分发、Session 处理等功能。
1、Github 主页:https://github.com/visionmedia/express
2、官方网站:http://expressjs.com
npm 自定义配置 文件下载路径
Nodejs 内置的npm默认会把模块安装在c盘的用户AppData目录下,由于自己的C盘比较下,一切都放在 D盘中,所以重新设置了下载保存的路径。
- 用cmd命令进行查看当前电脑的npm 安装路径。
输入 npm config ls
- 接着在要保存的路径下创建两个文件夹:node_global_modules 和 node_cache
npm config set prefix “D:\VM\nodejs\node_global_modules”
npm config set cache “D:\VM\nodejs\node_cache” - 在用户文件加下,修改 .npmrc 文件
修改
查看
- 测试下载,下载内容是否到指定目录。
npm install -g express@version
-g 添加全局执行环境,安装时可以设定安装的版本信息,添加后缀 @version(具体版本号)。
注意:《Node.js 开发实战详解》清华大学出版社 作者黄丹华
书中明确使用 express app 创建了 app 项目, 其实express --help就出现上面的原因了
express3+已经把创建一个APP的功能分离出来为express-generator,没它创建不了应用程序
- 之后再每次使用 express 创建 app 项目的时候,使用 npm install express,由于网速的原因,此次没有实例成功。
- 紧接着,npm install -g express-generator 执行成功后会在全局的文件夹下有。express.cmd,执行这个内容,可以得到类似于 express app 项目
- 紧接着执行 app.js ,执行 node app.js 会报错,我执行的是 npm start 报出同样的错。
- 紧接着,一直下载缺少的模板。运行,直到错误解除。
npm的.npmrc文件在哪里?缓存及全局包文件在什么位置?
- 修改 .npmrc 文件,
npm config edit
,也可以直接到本地用户文件夹进行修改。 - 查看 .npmrc 文件目录,
npm config ls -l
- 获得 缓存目录
npm config get cache
- 获得 node 全局 node 包
npm config get prefix
2.2 Node.js 设计模式
模块与类
模块中的继承
- 动态继承
- 父类 person.js
- 学生子类 student.js
- 教师子类 teacher.js
- 程序猿子类 coder.js
- 测试类 app.js
- 重写父类中的方法
- person.js
- overload.js
- 静态的继承
- person.js
student.js 和 index_test.js
student_static.js 和 static_index.js
1、单例模式
2、适配器模式
将一个类的接口转关成客户希望的另外一个接口
3、装饰模式
动态地给一个对象添加一些额外的职责,就功能扩展而言,比生成子类更加的灵活。
4、工厂模式
定义一个用于创建对象的接口,让子类决定将哪一个类实例化,使用工厂使一个类的实例化延迟到其子类。