NodeJs 简介
NodeJs 是一个 JavaScript 运行环境,它让 JavaScript 能够开发后端程序,简直能实现其它后端语言能实现的所有性能。是一个基于 Chrome V8 引擎的 JavaScript 运行时
NodeJs 善于解决高并发。它不会为每个客户连贯创立一个新的线程,而仅仅应用一个线程。当有用户连贯了,就会触发一个外部事件,通过非阻塞 I /O,事件驱动机制,让 NodeJs 程序宏观上也是并行的
对于过程和线程:过程:负责为程序的运行提供必备的环境。相当于工厂中的车间
线程:计算机中的最小计算单位,线程负责执行过程中的程序。相当于工厂中车间的工人
JS 是单线程的
NodeJS 文档:http://nodejs.cn/learn
NodeJs 的装置
下载地址:http://nodejs.cn/download/
验证 NodeJs 是否装置胜利:在 cmd 中输出命令 node -v,若显示版本号则装置胜利
命令行窗口(cmd)
相干罕用的命令:dir:列出当前目录下的所有文件或子目录
cd 目录名:进入到指定的目录
md 目录名:创立一个文件夹
rd 目录名:删除一个文件夹
磁盘名::进入到对应的磁盘
cd ./:示意当前目录
cd ../:示意上一级目录
cd /:返回根文件夹
当咱们在命令行窗口关上一个文件,或调用一个程序时,零碎会首先在当前目录下寻找文件程序,如果找到了则间接关上
如果没有找到,则会顺次到环境变量中的 path 的门路中寻找
如果还是没有找到,则会报错
注:咱们能够将一些常常须要拜访的程序好文件的门路增加到 path 中,这样咱们能够在任意地位来拜访这些文件和程序了
运行 NodeJs 程序
在 cmd(或者编译软件中内置的控制台)中,进入到对应的要运行的文件夹,而后输出命令:node 要执行的文件名
要运行谁,就 node 谁
NodeJs 自启动工具
supervisor / nodemon(集体举荐)/...:可能不停地监听 NodeJs 的文件,进行实时批改
supervisor 的装置:npm install -g supervisor
nodemon 的装置:npm install -g nodemon(官网:https://nodemon.io/)应用:可用 supervisor/nodemon 来代替 node 命令:supervisor/nodemon 要执行的文件名
NodeJs 中的一些输入命令
console.log('...') // 一般输入语句
console.dir('...') // 显示一个对象所有的属性和办法,残缺的显示出对象(在相似 json 的树中打印元素)console.error('...') // 正告输入
console.time(标识) // 计时开始
console.timeEnd(标识) // 计时完结
console.assert(表达式,输入文字) // 当表达式为假时,输入文字(抛出谬误),否则不输入文字
对于 npm,包
包(package):CommonJS 的包标准由包构造和包形容文件两个局部组成
包构造:用于组织包中的各种文件
包构造实际上是一个压缩文件,其中蕴含以下的一些文件:pachage.json:形容文件(必须的)bin:可执行二进制文件
lib:js 代码
doc:文档
test:单元测试
包形容文件:形容包的相干信息,表白非代码的相干信息,以供内部读取剖析(json 格局的文件 --package.json)创立 package.json 文件的命令:npm init(须要手动抉择)/npm init -y(默认全副 yes)package.json 的罕用属性:name:项目名称
version:版本号
description:我的项目形容
main:主模块
dependencies:依赖包列表
devDependencies:开发时的依赖
scripts:脚本(可应用 npm 命令执行)license:开源协定
新版的 nodejs 曾经集成了 npm,所以装置 node 的同时,npm 也一起装置好了
对于 node 而言,npm 帮忙其实现了第三方模块的公布,装置和依赖等
npm 相干命令:npm -v:查看 npm 版本
npm version:查看所有模块的版本
npm search 包名:搜寻模块包
npm install 包名:在当前目录安装包
npm install 包名 @版本号:在当前目录装置对应版本的包
npm install 包名 -g:全局模式安装包
npm install 包名 --save:安装包并增加到依赖中(npm install 会主动下载以后我的项目依赖中的包)npm install 包名 --save-dev:安装包并增加到开发时依赖列表
npm remove 包名:删除包
npm uninstall 包名:卸载包
npm view 包名:查看包
npm install 文件门路:从本地装置
npm install 包名 -registry= 地址:从镜像源装置
npm config set registry 地址:设置镜像源
npm update 包 / 模块名:更新包 / 模块
npm cache clear:清空 npm 本地缓存
从 npm 装置的 包 / 模块 都会放到 node_modules 文件夹中(上传我的项目时不会把 node_modules 都上传)node 在应用模块名字来引入模块时,他会首先在当前目录的 node_modules 中寻找是否含有该模块,如果有则间接应用,如果没有则间接去上一级目录的 node_modules 中寻找,直到找到为止,若直到找到磁盘的根目录仍然没有,则报错
有时候对于一些大的包,用 npm 装置下载会很慢,能够利用 cnpm 来装置下载
装置 cnpm:npm install -g cnpm --registry=https://registry.npm.taobao.org
若在 npm 安装包时,总是提醒 npm resource busy or locked... 的报错,解决办法:npm cache clean
npm install
npm 官网:https://www.npmjs.com/
NodeJs 作用域
NodeJs 中一个文件就是一个模块
模块中应用 var 定义的变量为部分作用域,只能在该模块中应用。因为模块在应用时会把 NodeJs 编译为一个函数,那么应用 var 的定义的变量,天经地义只能在这个模块(函数)中应用
如:在某个模块中编写了 var a=100;
NodeJs 在执行前,编译这个模块为:function(exports,require,module,__filename,__dirname){var a=100;}
全局对象:global. 属性 / 办法(相似于 window)global.name='xxx'(应用时 global 关键字可省略不写)
NodeJs 的模块化
NodeJs 采纳模块形式治理和组织代码,NodeJs 所有的性能都存在每个模块中
一个具备特定性能的文件就是一个模块,模块间可能存在肯定的依赖关系,应用模块能够很好地把这些依赖关系整合起来
模块标准:AMD:异步模块定义,异步的加载模块,requirejs 利用了这一标准,适宜客户端浏览器环境
CMD:是 seajs 推崇的标准(相当于 AMD 和 CommonJs 的联合再加上其余货色)CommonJs:NodeJs 采纳了此标准来定义模块,但其采纳的是同步加载文件形式,只实用于服务端
exports 导出(裸露)对象:因为 nodejs 是基于模块化治理,所有用户编写的代码都是部分的,要与其它模块共享数据能够应用裸露对象
module 模块对象:module.exports(真正的裸露对象)若要对外裸露属性或办法,就用 exports 就行(exports 只能应用. 的形式来向外裸露外部变量)若要裸露对象(如 class,蕴含了很多属性和办法),就用 module.exports(module.exports 能够通过. 的形式,也能够间接赋值)require 函数:引入(加载)模块
require 办法的外部加载十分复杂,其加载的优先级也各不相同,如下图:
NodeJs 的模块分类:自定义模块:咱们本人编写的模块
第三方模块:第三方开发者奉献的模块(npm install 包名)零碎(内置)模块:NodeJs 官网开发的模块
以上模块可用 require 函数引入:var xxx=require('xxx')(若为外围模块(零碎的),则 xxx 为模块名,若为文件模块(用户自定义的),则 xxx 为绝对应的模块相对路径(./ 不能省略))实际上模块中的代码都是包装在一个函数中执行的,并且在函数执行时,同时传递了 5 个实参:exports:该对象用来将变量或函数裸露到内部
require:函数,用来引入内部的模块
module:代表的是以后模块自身,exports 是 module 的属性
__filename:以后模块文件的残缺门路
__dirname:以后模块所在文件夹的残缺门路
内置模块 —HTTP 模块
HTTP 协定:网络是信息传输,接管,共享的虚构平台
网络传输数据有肯定规定,即称为协定。HTTP 协定就是其中一种,也是应用最频繁的一种
HTTP 协定是 TCP/IP 协定之上的一个应用层协定,用于定义 WEB 浏览器与 WEB 服务器之间替换数据的过程及数据自身的格局。采纳的是 申请 / 应答 形式来传递数据(一次申请对应一次应答)HTTP 模块是基于 HTTP 协定的通信模块,可用于创立 HTTP 服务器,也可作为客户端向其余服务器发动申请
引入 HTTP 模块:var http=require('http')
HTTP 模块中的某些办法:(更多办法可查看文档)HTTP 服务端的办法:1. http.createServer([options][, requestListener]):创立 Web 服务
http.createServer((req, res) => { //req 获取 url(客户端)传过来的信息,res 给浏览器响应信息
// 应用此回调解决每个独自的申请
res.writeHead(200,{"Content-type":"text/html;charset=utf-8"}); // 设置响应头(状态码是 200,文件类型是 html,字符集是 utf-8)(设置 charset=utf- 8 可解决中文乱码问题)res.write('xxx'); // 页面上显示 xxx 内容
res.end(); // 完结响应}).listen(监听的端口号)
HTTP 客户端的办法:1. http.get(url(指标地址)[, options][, callback]) / http.get(options[, callback]):模拟客户端从服务端获取数据(将申请办法设为 GET 申请)它将申请办法设置为 GET 并且会主动调用 req.end()
callback 调用时只有一个参数:res(返回对象,接管到服务器响应的所有内容)var request=http.get({host:'localhost',path:'/user?name=helios&age=22',port:3000},
function(res){res.setEncoding('utf-8');
res.on('data',function(data){console.log('服务端相应回来的数据为:'+data);
})
});
2. http.request(url(指标地址)[, options][, callback]) / http.request(options[, callback]):发动 http 申请
callback 调用时只有一个参数:res
var req = http.request(options,(res)=>{res.setEncoding('utf-8');
res.on('data',(data)=>{console.log(data);
});
});
内置模块 —fs 模块
文件系统模块,用于对操作系统中的文件进行相干操作
常见的操作有:读文件,写文件,删除文件等
引入 fs 模块:var fs=require('fs')
读文件:间接读取(将硬盘上的所有内容全副读入内存后才触发回调函数)和流读取(将数据从硬盘中读取一节就触发回调函数,实现大文件操作)间接读取:同步读取(fs.readFileSync('xxx(文件名))异步读取(fs.readFile('xxx(文件名)',function(err,txt){...}))写文件:引入 fs 模块后,找到要写入的内容,开始写入
异步写文件:fs.writeFile()
fs.writeFile('xxx(文件名)',data(写入的数据),function(err){...})
同步写文件:fs.writeFileSync()
fs.writeFileSync('xxx(文件名)',data(写入的数据))
删除文件:fs.unlink('xxx(文件名)',function(err){...})
fs.unlinkSync('xxx(文件名)')
删除非空目录:1. 读取目录中的文件及文件夹列表:fs.readdir();
2. 读取每一个文件的详细信息:fs.stat();
3. 判断如果是文件,则间接删除:fs.unlink();
4. 若如果是目录,则递归调用本人
5. 删除底下的空目录:fs.rmdir();
具体实现(同步形式):const fs=require("fs");
function deldir(path) {let files = [];
if(fs.existsSync(path) ) { // 先查看是否有含此门路的目录
files = fs.readdirSync(path); // 读取目录中的文件及文件夹列表
files.forEach(function(f,i){
let curPath = path + "/" + f;
if(fs.statSync(curPath).isFile()) { // 若是文件,则间接删除
fs.unlinkSync(curPath);
} else { // 若是目录则调用本身函数进行递归
deldir(curPath);
}
});
// 删除空目录
fs.rmdirSync(path);
}
}
deldir('xxx(要删除的目录)');
读取文件信息:fs.stat('文件名',function(err,state){
/*
state 是文件的信息对象
蕴含罕用的文件信息:size:文体大小, 字节
mtime:文件批改工夫
birthtime:文件创建工夫
...
蕴含的一些办法:.isFile():判断以后查看的对象是不是一个文件
.isDirectory():判断以后查看的对象是不是一个目录(文件夹)...
*/
})
测验门路是否存在:fs.existsSync(path)
读取一个目录的目录构造:fs.readdir(path[,options],function(err,files){...}); //files 是一个字符串数组,每个元素就是一个文件夹或文件的名字
fs.readdirSync(path[,options]);
截断文件(将文件批改为指定大小):fs.truncate(path,len,callback);
fs.truncateSync(path,len);
创立目录:fs.mkdir(path[,mode],callback);
fs.mkdirSync(path[,mode]);
删除(空)目录:fs.rmdir(path,callback);
fs.rmdirSync(path);
重命名文件和目录:fs.rename(oldpath,newpath,callback);
fs.renameSync(oldpath,newpath);
监督文件更改写入:fs.watchFile(filename[,options],listener(curr,prev)); //listener 为回调函数,当文件发生变化时,回调函数会执行(参数:curr 为以后文件状态,prev 为批改前文件的状态)追加文件内容:fs.appendFile('文件名','追加的内容',(err)=>{...})
创立文件并笼罩写入内容:fs.writeFile('文件名','内容',(err)=>{...})
流:一组有序的,有终点和起点的字节数据的传输方式
在应用程序中各种对象之间替换与传输数据时,总是将该对象中所蕴含的数据转换为各种模式的流数据(字节数据),在通过流的传输,达到目标对象后再将流数据转换为该对象中可应用的数据
四种流类型:Readable(可读),Writable(可写),Duplex(可读可写),Transform(操作被写入数据,而后读出后果)解决流事件:data(有数据可读时触发),end(没有更多的数据可读时触发),error(在接管和写入过程中产生谬误时触发),finish(所有数据已被写入到底层零碎时触发)读取文件流:var readerStream=fs.createReadStream('xxx(文件名)'); // 创立可读流
readerStream.on('data',function(chunk){ // 监听 data 事件,有数据读取进去就会触发,接管到数据
...
});
readerStream.on('end',function(){}); // 监听 end 事件,当文件读取结束时,触发该事件
readerStream.on('error',function(){}); // 监听 error 事件,当文件读取出错时,触发该事件
解决从流中读取数据中文乱码的问题:加上 readerStream.setEncoding("UTF8");
写入文件流:var writerStream=fs.createWriteStream('xxx(文件名)'); // 创立可写流
writerStream.write('xxxx(写入的内容)',["UTF8"]); // 写入流
writerStream.end(); // 写完当前完结
writerStream.on('finish',function(){...}); // 绑定一个 finish 事件来表明写入胜利
writerStream.on('error',function(){}); // 监听 error 事件,当文件读取出错时,触发该事件
管道(pipe):提供了一个输入流到输出流的机制。通常咱们用于从一个流中获取数据并将数据传递到另一个流中,这样能够缓缓实现大文件的复制过程(输入流.pipe(输出流))具体实现:// 创立一个可读流
var readerStream=fs.createReadStream('xxx(文件名)');
// 创立一个可写流
var writerStream=fs.createWriteStream('xxxx(文件名)');
// 管道读写操作
readerStream.pipe(writerStream);
链式流:通过连贯输入流到另外一个流并创立多个流操作链的机制
链式个别用于管道操作
可用管道和链式来压缩和解压文件
压缩文件:(将 xxx 文件压缩为 xxx.gz)var fs=require('fs');
var zlib=require('zlib');
fs.createReadStream('xxx(文件名)').pipe(zlib.createGzip()).pipe(fs.createWriteStream('xxx.gz'));
解压文件:(将 xxx.gz 解压为 xxx 文件)var fs=require('fs');
var zlib=require('zlib');
fs.createReadStream('xxx.gz').pipe(zlib.createGunzip()).pipe(fs.createWriteStream('xxx(文件名)'));
内置模块 —path 模块
可用来解决与转换文件门路
用于格式化或拼接一个残缺的门路
引入 path 模块:var path=require('path');
path 上的办法:较不太罕用的:path.normalize(p); // 规范化门路(留神./ 和../)path.join(path1,path2,...); // 用于连贯门路,该办法的主要用途是会正确应用以后零碎的门路分隔符(Unix 零碎是 '/',Windows 零碎是 '\')path.resolve([from...],to); // 将 to 参数解析为绝对路径。取得相对路径的绝对路径计算(会应用第一个参数作为第二个参数的基准)path.isAbsolute(path); // 判断 path 是否为绝对路径
path.relative(from,to); // 将门路转为相对路径
path.dirname(path); // 返回门路中代表文件夹的局部
path.basename(path[,ext]); // 返回门路中的最初一部分
path.extname(path); // 返回门路中文件的后缀名(即门路中最初一个 '.' 之后的局部),若门路中并不蕴含 '.' 或该门路中只蕴含一个 '.',且这个 '.' 为门路的第一个字符,则此命令返回空字符串
较为罕用的:path.parse(pathString); // 返回门路字符串的对象
path.format(pathObject); // 从对象中返回门路字符串
内置模块 —url 模块
url:寰球对立资源定位符,对网站资源的一种简洁表达形式,也称为网址
引入 url 模块:var path=require('url');
url 被解析时,会返回一个 url 对象,它蕴含每个组成部分作为属性
url 的形成(从左到右):1. 残缺构造
协定:// 用户名: 明码 @主机名. 名. 域: 端口号 / 目录名 / 文件名. 扩展名? 参数名 1 = 参数值 1 & 参数名 2 = 参数值 2 &...#hash
2. http 协定的 URL 常见构造
协定:// 主机名. 名. 域 / 目录名 / 文件名. 扩展名? 参数名 1 = 参数值 1 & 参数名 2 = 参数值 2 &...#hash
提供了两套对于 url 进行解决的 API 性能:1. 旧的 node.js url 模块
应用传统的 API 解析 URL 字符串:const xxx=url.parse('https://user:pass@sub.host.com:8080/p/a/t/h?query=string#hash');
2. 新的 url 模块(WHATWG URL 规范模块)WHATWG 的 URL 接口:
应用 WHATWG 的 API 解析 URL 字符串:
const xxx=new url.URL('https://user:pass@sub.host.com:8080/p/a/t/h?query=string#hash');
属性:xxx.hash:获取及设置 URL 的分段(hash)局部
xxx.host:获取及设置 URL 的主机(host)局部
xxx.hostname:获取及设置 URL 的主机名(hostname)局部
xxx.href:获取及设置序列化的 URL
xxx.origin:获取只读序列化的 URL origin 局部
xxx.pathname:获取及设置 URL 的门路(path)局部
xxx.search:获取及设置 URL 的序列化查问(query)局部
内置模块 —Query String 模块
用于解决 query(参数)字符串
模块提供用于解析和格式化 URL 查问字符串的实用工具
引入 Query String 模块:var qs=require('querystring');
将 query 字符串变成 query 对象:qs.parse(str) //qs.decode() 是此办法的别名
还可依据某个符号进行切分键值对和键值:qs.parse(str,'先依据什么符号来切分键值对','再依据什么符号来切分键和值')
e.g.
let str='name-aa#pass-123#sex-0';
let obj=qs.parse(str,'#','-');
输入 obj 的后果为:{name:'aa',pass:'123',sex:'0'}
将 query 对象变成 query 字符串:qs.stringfy(obj); //qs.encode() 是此办法的别名
还可依据某个符号进行切分键值对和键值:qs.stringfy(str,'先依据什么符号来切分键值对','再依据什么符号来切分键和值')
e.g.
let obj={name:'aa',pass:'123',sex:'0'}
let str=qs.stringfy(obj,'^','?');
输入 str 的后果为:'name?aa^pass?123^sex?0'
对 URL 查问字符串的特定要求进行了优化的形式,对给定的 str 执行 URL 百分比编码:qs.escape(str);
在给定的 str 上执行 URL 百分比编码字符的解码:qs.unescape(str);
内置模块 —events 模块
只提供了一个对象:events.EventEmitter
EventEmitter 的外围就是事件触发与事件监听器性能的封装
所有这些产生事件的对象都是 event.EventEmitter 的实例
引入 events 模块:var events=require('events');
创立 eventEmitter 对象:var eventEmitter=new events.EventEmitter();
单事件监听:var events=require('events');
var eventEmitter=new events.EventEmitter();
eventEmitter.on('xxx(事件)',function(arg){...});
setTimeout(function(){eventEmitter.emit('xxx(对应下面的事件)','参数'); // 要调用 emit 办法对应的事件才会被触发(依照监听器注册的程序,同步地调用每个注册到名为 xxx 的事件的监听器,并传入提供的参数)},1000)
多事件监听:EventEmitter 的每个事件都由一个事件名和若干个参数组成。反对若干个事件监听器
当事件触发时,注册到这个事件的事件监听器被顺次调用,事件参数作为回调函数参数传递
var events=require('events');
var eventEmitter=new events.EventEmitter();
eventEmitter.on('xxx(事件)',function(arg){内容 1});
eventEmitter.on('xxx(事件)',function(arg){内容 2});
setTimeout(function(){eventEmitter.emit('xxx(对应下面的事件)','参数'); // 要调用 emit 办法对应的事件才会被触发(依照监听器注册的程序,同步地调用每个注册到名为 xxx 的事件的监听器,并传入提供的参数)},1000)
无关 EventEmitter 的一些办法:
无关 EventEmitter 的类办法:
无关 EventEmitter 的事件:
error 事件:EventEmitter 定义了一个非凡事件:error,它蕴含谬误的语义,在遇到一场时通常会触发 error 事件
当 error 触发时,EventEmitter 规定如果没有响应的监听器,Nodejs 会把他当做异样,退出程序并输入错误信息
ar events=require('events');
var eventEmitter=new events.EventEmitter();
eventEmitter.emit('error');
继承 EventEmitter:大多数状况下,咱们不会间接应用 EventEmitter,而是在对象中继承它
包含 fs,net,http 在内的,只有是反对事件响应的外围模块都是 EventEmitter 的子类
这样做的起因:1. 具备某个实体性能的对象实现事件合乎语义,事件的监听和产生应该是一个对象的办法
2. JavaScript 的对象机制是基于原型的,反对局部多重继承,继承 EventEmitter 不会打乱对象原有的继承关系
第三方模块 —nodemailer
一个简略易用的 Node.JS 邮件发送模块(通过 SMTP,sendmail,或者 Amazon SES),反对 unicode
nodemailer 的次要特点:反对 Unicode 编码
反对 Window 零碎环境
反对 HTML 内容和一般文本内容
反对附件 (传送大附件)
反对 HTML 内容中嵌入图片
反对 SSL/STARTTLS 平安的邮件发送
反对内置的 transport 办法和其余插件实现的 transport 办法
反对自定义插件解决音讯
反对 XOAUTH2 登录验证
利用场景:注册案例(发送邮箱验证码)nodemailer 的官网:https://nodemailer.com/about/
nodemailer 的装置:npm install nodemailer
nodemailer 的应用:"use strict";
const nodemailer = require("nodemailer");
// 当您没有真正的邮件帐户进行测试时才须要创立测试账户
let testAccount = await nodemailer.createTestAccount();
// 创立发送邮件的对象(若是大型企业的发送方,可通过此模块下的文件夹 lib/well-know/service.json 查找对应企业的相干信息)let transporter = nodemailer.createTransport({
host: "smtp.ethereal.email", // 发送方的邮箱 smtp
port: 587, // 端口号
secure: false, // true for 465(port), false for other ports
auth: {
user: testAccount.user, // 发送方的邮箱地址
pass: testAccount.pass, // mtp 验证码
},
});
// 邮件的相干信息
let mailObj={
from: '"Fred Foo" <foo@example.com>', // 发送方邮箱
to: "bar@example.com, baz@example.com", // 接管方邮箱
subject: "Hello", // 邮件题目
text: "Hello world?", // 邮件文本信息
html: "<b>Hello world?</b>", // 邮件的 html 显示局部(和 text 局部两者只能抉择一个)};
// 发送邮件
let info = await transporter.sendMail(mailObj,(err,data)=>{...});
在 qq 邮箱中设置 SMTP 服务:qq 邮箱首页 --> 账户 --> POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV 服务(点击对应的 SMTP 服务开启即可)
缓存区 Buffer
像一个数组,专门用来存储二进制数据,它的元素显示为 16 进制的两位数(实际上一个元素就示意内存中的一个字节(8bit))Buffer 中的内存不是通过 JavaScript 调配的,而是在底层通过 C ++ 申请的
能够间接通过 Buffer 来创立内存空间
Buffer 的大小一旦确定,则不能被批改
创立一个指定大小的 Buffer:1. var buf=new Buffer(xx) / var buf=new Buffer([...])(按指定数组创立缓存区);(buffer 构造函数是不举荐应用的)2. var buf=Buffer.alloc(xx);(罕用)3. var buf=Buffer.allocUnsafe(xx);(buffer 中可能含有敏感数据)通过索引来批改操作 buf 中的元素:buf[x]=xxx
通过索引来查看 buf 中的元素:buf[x]
将一个字符串 str 转换为 buffer:Buffer.from(str)
将一个 buffer 中的数据转换为字符串显示进去:buf.toString()
写入内容到缓存区:buf.write('xxx')
缓存区的拷贝(复制):buf1.copy(buf2) //buf1 复制给 buf2
NodeJs REPL(交互式解释器)
"读取 - 求值 - 输入" 循环(Read-Eval-Print Loop),是一个简略的,交互式的编程环境
Node 自带交互式解释器,可执行以下工作:读取:读取用户输出,解析输出了 Javascript 数据结构并存储再内存中
执行:执行输出的数据结构
打印:输入后果
循环:循环操作以上步骤直到用户两次按下 ctrl c 按钮退出
在 cmd 中输出命令 node 启动 Node 终端,即可在 > 后输出简略的表达式,并按下回车来计算结果
简略的表达式运算:xx+xx,xx-xx,xx*xx,xx/xx,xx+(xx+xx)/xx,...
多行表达式:如执行循环:
三个点的符号是回车换行后零碎主动生成的(Node 会自动检测是否为间断的表达式)应用变量:能够将数据存储在变量中,并在你须要的时候应用它
变量申明须要应用 var 关键字,如果没有应用 var 关键字变量会间接打印进去。应用 var 关键字的变量能够应用 console.log() 来输入变量
下划线变量:能够应用下划线获取上一个表达式的运算后果
REPL 的一些相干命令:ctrl+c:退出以后终端
ctrl+ c 按下两次:退出 Node REPL
ctrl+d:退出 Node REPL
向上 / 下:查看输出的历史命令
tab 键:列出以后命令
.help:列出应用命令
.break/.clear:退出多行表达式
.save filename:保留以后的 Node REPL 会话到指定文件
.load filename:载入以后的 Node REPL 会话的文件内容
NodeJs 回调函数
Nodejs 异步编程的间接体现就是回调
回调函数,又称为回调。将 a 函数作为参数传入 b 函数中,b 函数执行过程中依据机会或条件决定是否调用 a 函数,a 函数就是回调函数
在执行代码时没有阻塞或期待文件 I / O 操作,这就大大提高了 Nodejs 的性能,能够解决大量的并发申请
回调函数个别作为函数的最初一个参数呈现
阻塞代码:(同步)var fs=require('fs');
var data=fs.readFileSync('xxx');
console.log(data.toString());
console.log('程序执行结束');
非阻塞代码:(异步)var fs=require('fs');
fs.readFile('xxx',(err,data)=>{if(err){return console.error(error);
}
console.log(data.toString())
});
console.log('程序执行结束');
回调函数原理:以 setinterval(show,1000) 为例:
回调函数的用处:注册事件,异步函数,...
通常用于达到某个机会或条件时须要执行代码的状况,就应用回调函数
同步与异步:同步:一个工作期待前一个工作完结,而后再执行,程序的执行程序与工作的排列程序是统一的,同步的
情景:张三去买奶茶,前面排队的是李四。张三:给我来一杯卡布奇诺
服务员:没有卡布奇诺了
张三:啊,那我打电话问一下敌人看看他还要喝啥
此时服务员和李四都在等张三
随后张三打完电话,就对服务员说来一杯百香果吧
张三买完后,就轮到李四去买了
代码:console.log('1');
console.log('2');
for(var i=0;i<1000;i++){...}
console.log('3');(先循环完后再输入 3)异步:每一个工作有一个或多个回调函数,前一个工作完结后,不是执行后一个工作,而是执行回调函数,后一个工作则不等前一个工作完结就执行。所以程序的执行程序与工作的排列程序是不统一的,异步的
情景:张三去买奶茶,前面排队的是李四。张三:给我来一杯卡布奇诺
服务员:没有卡布奇诺了
张三:啊,那我打电话问一下敌人看看他还要喝啥
此时张三到队列的旁边打电话等着
随后就到李四买奶茶
李四买完后,此时张三就打完电话问敌人,就对服务员说那给我来一杯百香果吧
代码:console.log('1');
console.log('2');
setTimeout(function(){for(var i=0;i<1000;i++){...}
},1000);
console.log('3');(在这 1s 内,先输入 3,1s 后再循环)Nodejs 中共有三种异步实现形式:回调函数(回调函数不肯定是异步,但异步肯定是回调函数)事件(基于回调):事件源.on('事件名称', 回调函数)
Promise(es6):因为异步的返回后果工夫程序不可控,所以须要应用 promise 来对立管制输入后果
事件循环驱动
Nodejs 单线程相似进入一个 while(true) 的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件产生就调用该回调函数
Nodejs 应用事件驱动模型,当 web server 接管到申请,就把它敞开而后进行解决,而后去服务下一个 web 申请
当这个申请实现,它被放回解决队列,当达到队列结尾,这个后果被传递给用户
这个模型十分高效,可扩展性十分强,因为 web server 始终承受申请而不期待任何读写操作(以上可称为非阻塞式 I / O 或事件驱动 I /O)在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。事件相当于一个主体,而所有注册到这个事件上的处理函数相当于观察者
实现繁难爬虫(http 模块,…)
网络爬虫:是一种依照肯定的规定,主动地抓取万维网信息的程序或者脚本
可参考的相干步骤:1. 发动申请获取指标网站:http.get
2. 读取并剖析网站内容(html):可利用 cherrio 模块 cherrio 模块可应用 jq 的选择器
3. 获取无效信息(可利用正则表达式),下载(可利用管道实现)或其余操作
有下载图片操作的:
网页模块
动态网页:随着 html 代码的生成,页面内容和显示成果就根本不会发生变化了,除非你批改页面代码
动静网页:页面代码尽管没有变,但显示的内容能够随着工夫,环境或者数据库操作的后果再产生扭转
应用动静网页模板:模板:将一些固定的构造或体现间接以动态文件模式存储,将须要体现成动态数据的中央用模板语法进行编写,再用模板引擎读取该动态文件,将其余动静的数据替换进去。最终实现产生出一个动静的页面
为避免反复写相干的 html 代码,可把模板写成一个 html 文件,而后通过读取文件的形式读取该文件,再通过 res.render 函数来把相应的数据替换掉,造成一个动静批改数据的页面
对于服务器
服务器的两个概念:硬件服务器(电脑)软件服务器(软件)服务器要提供 HTTP 服务,就要装置一个服务器软件
服务器软件:apache,tomcat,iis,ngnix,node,...
服务器 ip(确定服务器主机的地位)和端口号(确定服务器里某个程序)拜访服务器:1. 关上浏览器
2. 输出网址:172.0.0.1(主机地址)localhost(当地主机,本地域名)局域网 IP(Windows 零碎可通过在 cmd 中输出命令 ipconfig 查看,Linux/MAC 零碎可输出命令 ifconfig 查看)局域网:服务器通过网线(无线)连贯,每一个电脑都会有一个 ip。(指在某一区域内由多台计算机互联成的计算机组)(不同局域网的 IP 地址能够反复,不会相互影响)外网(广域网):是一个遍布全世界的网络。它能够连贯极其大的物理范畴,属于近程性的网络,曾经实现了跨国互联。(是许多的计算机相互之间用线路连贯造成的)(外网 IP 地址不能反复)NodeJs 开启服务器:(不须要软件)1. 引入通信模块(http)2. 创立服务器
3. 监听 request 事件
4. 监听端口(Windows 零碎可通过在 cmd 输出命令 netstat - a 查看开启了哪些端口)
express 框架
express 官网:https://www.expressjs.com.cn/
express 特点:能够设置中间件响应或过滤 http 申请
能够应用路由实现动静网页,响应不同的 http 申请
内置反对 ejs 模板(默认是 jade 模板)实现模板渲染生成 html
本身性能极简,齐全由路由和中间件形成的一个 web 开发框架
装置 express:npm install express --save
引入 express 模块:var express = require('express')
创立 express 实例:var app = express();
监听 3000 端口,开启服务器
app.listen(3000,()=>{console.log('server start');
})
对于 req(申请对象)和 res(响应对象):req:申请对象,蕴含了所有客户端申请的数据,申请头,申请主体
res:响应对象,蕴含了所有服务器端发送给客户端的数据,响应头,响应主体
req 上的局部办法:1. req.url:获取到用户申请的网址
2. req.query:获取 url 上用户传过来的参数(get 申请的数据)3. req.body:接管 post 申请的数据
4. req.params. 参数名:匹配 url 网址上的数据(在接申请的中央去匹配,再通过语法进行接管)e.g. router.get('/xxx/:xx',()=>{res.send('<h1>'+req.params.xx+'</h1>')})
更多 req 上的办法:(具体可看 express 官网)
res 上的局部办法:1. res.writeHead(状态码, 响应头对象({"Content-Type":"text/html;charset=utf-8"})):设置响应头
响应头对象蕴含的属性有:Content-Type:响应的文件类型(未指定响应文件类型时,默认是 html,编码默认是零碎编码)Content-Length:响应内容的长度(长度是多少就响应多少的内容)Access-Control-Allow-Origin:设置跨域(值为 * 则为全副网站)...
波及的知识点:MIME 类型:可认为是文件类型的表述
常见的 MIME 类型:.html:text/html
.css:text/css
.js:text/javascript
.png:image/png
.jpg:image/jpeg
.gif:image/gif
.json:text(application)/json
.mp3:audio/mpeg
.mp4:video/mpeg
.pdf:application/pdf
.xml:text/xml
.txt:text/plain
...
2. res.write("xxx"):把响应的货色 xxx 返回到页面
3. res.end():完结响应
4. res.send('xxx'):返回任意类型(string,json,...)的数据给客户端(注:若返回的是一个数字类型的,会被当成状态码。此办法只能呈现一次,重复使用会有效和报错)5. res.status(状态码).send('xxx'):设置状态码并返回数据
6. res.json(data):返回 json 对象,主动设置响应头。个别针对 ajax 利用
7. res.render('模板名称',{ 数据}):读取模板文件并拼接数据,主动将后果发送给浏览器(会在模板的默认目录(views)下依据模板名称找对应的模块)8. res.download('xxx'):下载当前目录上面的 xxx 文件
res.download('xxx','yyy'):下载当前目录上面的 xxx 文件,并重命名为 yyy
9. res.redirect('xxx'):重定向到从指定的 url 门路 xxx
更多 res 上的办法:(具体可看 express 官网)
可通过 express 框架书写 api
通过 api 接口实现数据的申请
api 接口形成的因素:ip,port,pathname,methods(get,post),用户传递的数据(数据格式由后端确定)用 get 办法写一个 api 接口:
用 post 办法写一个 api 接口:
应用指定的回调函数将 HTTP GET 申请路由到指定的门路:
app.get('xxx(路由门路,默认为根门路'/')',(req,res)=>{...})(get 申请的数据可间接在网页网址上获取,通过 req.query 的办法来获取(也可通过软件 Postman 来进行接口测试))应用指定的回调函数将 HTTP POST 申请路由到指定的门路:
app.post('xxx(路由门路,默认为根门路'/')',(req,res)=>{...})(验证 post 申请的数据不可间接通过网页网址来获取, 在申请体里,通过 req.body 的办法来获取并用到第三方模块 body-parser 来进行解析传过来的表单或 json 或 formdata 数据。而后可通过软件 Postman 来进行接口测试)
express— 路由
路由:指如何定义利用的断点(URLs)以及如何响应客户的申请(接管用户申请,解决用户数据,返回后果给用户的一套程序)(可了解为生成动静网页的程序)后端路由的外围:URL
express 获取路由实例:var router=express.Router();
创立对应的路由:router. 申请形式(get/post/all)('/xx(申请地址)',(req,res)=>{...})
可创立一个独立的路由模块供应用:在 routers 目录下创立一个独立的文件来编写对应路由:var express=require('express');
var router=express.Router();
router.get('/xx',function(req,res){...})
module.exports=router;
而后在主文件 app.js 下引入该文件模块,即可援用对应的路由:const express=require('express');
const app=express();
let userRouter=require('xxx(下面编写路由的文件门路)')
app.use('/xxx(根门路)',userRouter); // 相当于对应的路由地址为:/xxx/xx...
路由的辨别:大路由(总路由):app.js 负责承受所有申请,对申请进行调配
小路由(分路由):routes 目录下的所有路由模块,只负责解决本人治理的目录下的申请
express—midelware(中间件)
中间件自身是一个函数,位于客户端和路由之间,可拜访申请对象和响应对象,也可调起下一个中间件。相当于拦截器
个别被命名为 next 的变量
next():执行下一个工作,若不调用则整个申请响应就会停止不会再往后执行
内置中间件:static(动态资源目录):指定一个目录,该目录可被拜访(等同于 apache 的 www)app.use('/xxx(可加可不加)',express.static('目录的绝对路径'))
自定义中间件:(要留神 next())全局定义:app.use('/(若是'/'示意根门路可默认不写)',(req,res,next)=>{console.log('中间件');
let {a}=req.query;
if(a){next(); // 是否往下继续执行
}
else{res.send('短少 a');
}
})
部分定义:app.get('/user/get',(req,res,next)=>{...},
(req,res)=>{...}
})
第三方中间件(body-parser(解析数据的中间件),multer(上传文件的中间件)等)利用级中间件绑定到 app 对象,应用 app.use() 和 app.METHOD(),其中 METHOD 是须要解决的 HTTP 申请的办法
定义错误处理中间件:须要 4 个参数
app.use((err,req,res,next)=>{console.error(err.stack);
res.status(500).send('xxx');
})
express— 模板引擎
views 放模板的文件目录:app.set('views','./views');
view engine 模板引擎:app.set('view engine','jade/ejs');
ejs 模板的局部语法:<% code %>:用于执行代码
<%= string %>:会进行 html 本义
<%- string %>:不会本义,原样输入
...(ejs 官网:https://ejs.bootcss.com/#promo)
express— 集成数据库
要为 express 利用增加连贯数据库的能力,只须要加载相应数据库的 Node.js 驱动即可
可连贯的数据库有:Cassandra,mysql,sql server,mongodb,redis 等(具体用法可查看官网)e.g. 连贯 mysql 数据库:
express— 会话治理 Session
会话是一种长久的网络协议,用于实现服务器和客户端间的一些交互行为(可进行身份验证...)一个会话可能蕴含屡次连贯,每次连贯都被认为是会话的一次操作
HTTP 协定是无状态的,自身不反对会话,为了在无状态的 HTTP 协定上实现会话,就有了 Cookie(保留在客户端浏览器中),Session(保留在服务器中)等来存储相干的信息
如果说 Cookie 机制是通过查看客户身上的 "通行证" 来确定客户身份的话,那么 Session 机制就是通过查看服务器上的 "客户明细表" 来确认客户身份。Session 相当于程序在服务器上建设的一份客户档案,客户来访的时候只须要查问客户档案表就能够了
cookie-parser 模块和 express-session 模块配合应用
Cookie 和 Session 的区别:
装置 cookie-parser:npm i cookie-parser
装置 Session:npm i express-session
cookie-parser 模块和 express-session 模块同时引入:const cookieParser=require("cookie-parser");
const session=require("express-session");
Session 的配置:app.use(session({option}))
option 的主要参数:name:cookie 的名字(原属性名为 key)(默认:’connect.sid’)store:session 存储实例
secret:用它来对 session cookie 签名,避免篡改
cookie:session cookie 设置(默认:{path: '/',httpOnly:true,secure:false,maxAge:` `null` `})genid:生成新 session ID 的函数(默认应用 uid2 库)rolling:在每次申请时强行设置 cookie,这将重置 cookie 过期工夫(默认:false)resave:强制保留 session 即便它并没有变动(默认:true, 倡议设为:false)proxy:当设置了 secure cookies(通过 'x-forwarded-proto' header)时信赖反向代理。当设定为 true 时,'x-forwarded-proto' header 将被应用。当设定为 false 时,所有 headers 将被疏忽。当该属性没有被设定时,将应用 Express 的 trust proxy
saveUninitialized:强制将未初始化的 session 存储。当新建了一个 session 且未设定属性或值时,它就处于未初始化状态。在设定一个 cookie 前,这对于登陆验证,加重服务端存储压力,权限管制是有帮忙的(默认:true)unset:管制 req.session 是否勾销(例如通过 delete,或者将它的值设置为 null)。这能够使 session 放弃存储状态但疏忽批改或删除的申请(默认:keep)设置 session:req.session. 属性名 = 属性值
获取 session:req.session. 属性名
从新设置 cookie 的过期工夫:req.session.cookie.maxAge=xxx
销毁 session:req.session.destroy(function(err){...})(当检测到客户端敞开时调用)刷新 session:req.session.reload()
初始化已有 session:req.session.regenerate()
保留 session:req.session.save()
Session 能够和 MongoDB 等数据库联合来做长久化的操作:
express— 闪存模块
connect-flash(flash)是一个在 session 中用于存储信息的特定区域
信息写入 flash,下一次显示结束后即被革除(只显示一次)典型的利用是联合重定向的性能,确保信息是提供给下一个被渲染的页面
装置 connect-flash 模块:var flash=require('connect-flash')
在 app.js 文件下编写,Express 应用这个插:app.use(flash());
利用:
express—express-generator 生成器
能够疾速生成一个根本的 express 开发框架
装置:npm install express-generator
创立我的项目:express -e 项目名称(主动创立我的项目目录)(- e 为 ejs 模板(举荐),若不加则为 jade 模板)express -e(手动创立我的项目目录)装置依赖:npm i
开启我的项目的形式:node app(举荐应用,要先在 app.js 的文件下编写监听相应的端口:app.listen(端口号,callback))npm start(主动查找当前目录下的 package.json 文件,找到 start 对应的命令进行执行)node ./bin/www
测试项目:关上浏览器,输出对应的网址
express 我的项目生成的文件夹 / 文件阐明:bin:可执行文件目录
node_modules:依赖包目录
public:动态文件根目录(搁置所有动态文件:动态 html,css,js,图片,字体,视频等)routers:路由模块目录,动静文件的目录(会优先找动态文件,若没有动态文件则找动静路由,若动静路由也没有,则 404)views:视图目录(寄存所有的页面模板)app.js:我的项目的主文件,对整个我的项目的所有资源进行兼顾的安顿
package.json:我的项目形容文件,申明我的项目的名称,版本,依赖等信息
以上是对 node 的局部整顿和总结,心愿有用,有什么倡议欢送提出哦!
大家一起提高~