Node.js
命令行窗口、cmd、终端、shell
-
常用的指令(windows系统)
dir 列出当前目录下所有文件
cd 目录名 进入到指定的目录
. 表示当前目录
… 表示上一级目录
md 目录名 创建一个文件夹
rd 目录名 删除一个文件夹
-
环境变量(windows系统中的变量)
path环境变量
-path中保存的是一个一个的路径,路径之间用;隔开
当我们在命令行窗口打开一个文件、或调用一个程序时
系统会首先在当前目录下寻找文件程序,如果找到了则直接打开
如果没有找到,则会依次到环境变量path的路径中寻找,直到找到位置
如果没有找到则报错
可以将经常需要访问的程序和文件的路径添加到path中,这样我们就可以在任意位置来访问这些文件和程序了
进程和线程
进程
- 进程负责为程序的运行提供必备的环境
- 进程相当于工厂中的车间
线程
- 线程是计算机中的最小的计算单位,线程负责执行进程中的程序
- 线程相当于工厂中的工人
单线程
- JS是单线程的,浏览器是单线程的
- Node处理请求时是单线程的,但是在后台有一个I/O线程池
多线程
- 传统的服务器都是多线程的
Node简介
-
Node.js是一个能够在服务器端运行的JavaScript的开放源代码、跨平台JavaScript运行环境
-
Node采铜的Google开发的V8引擎运行js代码,使用事件驱动、非阻塞和异步I/O模型等技术来提高性能,可优化应用程序的传输量和规模
-
Node时单线程的
-
Node的用途:
- Web服务API,比如REST
- 实现多人游戏
- 后端的Web服务,例如跨域、服务器端的请求
- 基于Web的应用
- 多客户端的通信,如即时通信
安装Node
命令行中找到指定的文件所在的目录,命令行中输入
node 文件名.js
模块化简介
ECMAScript标准的缺陷
-
没有模块系统
-
标准库较少
-
没有标准接口
-
缺乏管理系统
模块化
CommomJS的模块功能可以帮我们解决该问题
CommonJS的提出,主要是为了弥补当前JavaScript没有标准的缺陷
CommonJS对模块的定义十分简单
- 模块引用
- 模块定义
- 模块标识
在Node中,一个js文件就是一个模块
-
require( )可以传递一个文件的路径作为参数,node将会自动根据该路径来引入外部模块
-
这里路径,如果是痛相对路径,必须使用.或…开头
-
使用require引入模块以后,该函数会返回一个对象,这个对象代表的是引入的模块
-
在Node中,每一个js文件中的js代码都是独立运行在一个函数中,而不是全局作用域,一个模块中的变量和函数在其他模块中无法访问
语法:exports.属性(方法)
向外部暴露属性或方法,我们可以通过exports 来向外部暴露变量和方法
只需要将需要暴露的给外部的变量或方法设置为exports的属性或方法即可
语法:exports.函数名=function(){ }
模块化详解
模块标识:require()
我们使用require()引入外部模块时,使用的就是模块标识;我们可以通过模块的标识来找到指定的模块
模块分成两大类
核心模块
- 由node引擎提供的模块
- 核心模块的标识就是模块的名字
文件模块
- 由用户自己创建的模块
- 文件模块的标识就是文件的路径(绝对路径、相对路径)
在node中有一个全局对象global,和网页中的window类似
-
在全局中创建的属性,都会作为global的属性保存
-
在全局中创建的函数都会作为global的方法保存
arguments-函数实参
arguments.callee 这个属性保存的是当前执行的函数对象
node在执行模块中的代码时,它会现在代码的最顶部添加如下代码
function (exports,require,module,__filename,__dirname){
在代码的最底部,添加如下代码
}
世纪上模块中的代码都是包装在一个函数中执行的,并且在函数执行时,同时传递进了5个实参
-
exports 用来将变量或函数暴露到外部
-
require 函数,用来引入外部的模块
-
module 代表的当前模块本身,exports就是module的属性
既可以使用exports导出,也可以使用module.exports导出
-
__filename 当前模块的完整路径
-
__dirname 当前模块所在文件夹的完整路径
exports和module.exports
module.exports={
name:“猪八戒”;
age:28;
gender:“男”;
};
exports只能使用.的方式向外暴露内部变量
exports.xxx=xxx
module.exports既可以通过.的形式,也可以直接赋值
module.exports.xxx=xxx
Module.exports={ }
package包简介
CommonJS的包规范允许我们将一组相关的模块组合到一起,形成一组完整的工具
CommonJS的包规范由包结构和包描述文件两部分组成
包结构:用于组织包中的各种文件
包描述文件:描述包的相关信息,以供外部读取分析
-
包就是一个压缩文件,解压以后还原为目录。符合规范的目录,应该包含如下文件:
package.json 描述文件(必须)
(以下四个为文件夹)
bin 可执行二进制文件
lib js代码
doc 文档
test 单元测试
包描述文件-用于表达非代码相关的信息,它是一个JSON格式的文件-package.json,位于包的根目录下,是包的重要组成部分
-
package.json中的字段
name、description、version、keywords、author、bin、main、devDependencies、os、cpo、engine、licenses、bugs 等等
json文件不能写注释
NPM简介
Node Package Manager
Node包管理器
对于Node而言,NPM帮助其完成了第三方模块的发布、安装和依赖等。借助NPM,Node与第三方模块之间形成了一个很好的生态系统。
npm命令
-
npm -v 查看npm的版本
-
npm version 查看所有模块的版本
-
npm 帮助说明
-
npm search 包名 搜索包
-
npm install 包名 安装包
-
npm init 根据提示创建package.json文件
-
npm remove 包名 删除包
-
npm intall 包名 --save 安装包并添加到依赖中 ****,安装的同时,并设置为依赖
-
npm install 下载当前项目所依赖的包
-
npm intall 包名 -g 全局安装包(全局安装的包一般都是一些工具)
配置cnpm
镜像服务器
淘宝镜像
node搜索包的流程
通过npm或者cnpm下载的包都放到node_modules文件中
我们通过npm下载的包,直接通过包名引入即可
node在使用模块名字来引入模块时,他会首先在当前目录的node_modules中寻找是否含有
如果有则直接使用,如果没有则会去上一级目录的node_modules中寻找
如果有则直接使用,如果没有则再去上一级目录寻找,知道找到为止
直到找到磁盘的根目录,如果依然没有,则报错
Buffer缓冲区
buffer缓冲区
buffer的结构和数组很像,操作的方法也和数组类似,它的元素是16进制两位数
Buffer中存储的都是二进制数据,但是在显示时都是以16金志的形式显示
数组中不能存储二进制文件,而buffer就是专门用来存储二进制数据
使用bufffer不需要引入模块,直接使用即可
buffer中的每一个元素的范围是00-ff,buffer中的一个元素,占用内存的一个字节
var str="hello world";
var buf=Buffer.from(str);
//将一个字符串转换为buffer
consle.log(buf);
buffer的所有构造函数都是不推荐使用的
var buf2=Buffer.alloc(10);//创建
通过索引,来操作buf中的元素
Buffer的大小一旦确定,则不能修改,Buffer实际上是对底层内存的直接操作
var buf2=Buffer.alloc(10);
//alloc分配内存,还要清空原数据
var buf3=Buffer.allocUnsafe(10);
//allocUnsafe只分配内存,不清空原数据
//可能包含敏感数据
Buffer.from()
Buffer.toSring()可以将缓冲区中的数据转换为字符串
Buffer.alloc()
Buffer.allocUnsafe()
同步文件写入
文件系统file system
文件系统简单来说就是通过Node来操作系统文件
Node中,与文件系统的交互是非常重要的,服务器的本质就是将本地的文件发送给远程的客户端
Node通过fs模块和文件系统进行交互
使用文件系统,需要先引入fs模块,直接引入不需要下载
var fs=require("fs");
fs模块中所有的操作都会有同步和异步两种
-
同步文件系统会阻塞程序的执行,也就是除非操作完毕,否则不会向下执行代码
-
异步文件系统不会阻塞程序的执行,二水在操作完成时,通过回调函数将结果返回
文件的写入
fs.openSync(path, flags[,mode])
-
path 要打开文件的路径
-
flags 打开文件要做的操作的类型 r 只读的 w 只写的
-
mode可选择,设置文件的操作权限,一般不传
-
该方法会返回一个文件的操作描述符作为结果,我们可以通过访问描述符来对文件进行各种操作
var fs=require("fs");
var fd=fs.openSync("helloc.txt","w");
fs.writeSync(fd,string[,position[,encoding]]);
- fd 为没空啊蠓操作符,需要传递要写入的文件的描述符
- string 要写入的内容
- position 写入的起始位置(一般都不传)
- encoding 写入的编码,默认utf-8 一般也不传
fs.writeSync(fd,"今天天气真不错~~~",20);
fs.closeSync(fd)
- fd 要关闭的文件的描述符
fs.closeSync(fd);
异步的文件写入
引入fs模块
var fs=require("fs");
打开文件
fs.open(path,flags[,mode],callback)
异步调用的方法,结果都是通过回调函数的参数返回的
回调函数的两个参数:err:错误对象 fd:文件的描述符
fs.write(path, string[,position[,encoding]],callback)
fs.open("hello2.txt","w",function(err,fd){
//判断是否出错
//回调函数后执行
if(!err){
fs.write(fd,"这是异步写入的内容",function(err){
if(!err)
console.log("写入成功~");
fs.close(fd,function(err){
if(!err)
console.log("文件已关闭~");
})
});
console.log(fd);
}
else
console.log(err);
});
简单文件写入
异步fs.writeFile(file,data[,options],callback)
同步fs.writeFileSync(file,data[,options])
- file 要操作的文件的路径
- data 要写入的数据
- options 选项,可以对写入进行一些设置,一般都是一个对象
- encoding默认utf-8
- mode 模式
- flag w/r等(和C里面文件操作的w/r/a类似)
- callback 当前写入完成以后执行的函数
var fs=reqires("fs");
fs.writeFile("hello3.txt","这是写入的内容",function(err){
if(!err){
console.log("写入成功~~");
}
});
流式文件写入
无论同步、异步还是简单文件的写入都不适合大文件的写入,性能较差,容易导致内容溢出
fs.createWriteStream(path[,options])
- path 文件路径
- options 配置的参数
可以通过监听流的open和close事件来监听流的打开和关闭
var fs=require("fs");
//流式文件写入
//创建一个可写流
var ws=fs.createWriteSteam("hello3.txt");
ws.write("这是通过可写流写入文件的内容");
ws.write("这是通过可写流写入文件的内容");
//可以分多次写入
ws.once("open",function(){
console.log("流打开了");
});//on绑定一个长期有效的事件,one绑定一次性的事件
ws.once("close",function(){
console.log("流关闭了");
});
//on(事件字符串,回调函数)
//可以为对象绑定一个长期有效的事件
//once(事件字符串,回调函数)
//可以为对象绑定一个一次性的事件,该事件将会在触发一次以后自动失效
ws.end();
文件的读取
-
同步文件读取
-
异步文件读取
-
简单文件读取
-
流式文件读取
简单文件读取
fs.readFile(path][,options],callback)
fs.readFile(path[,options])
- path 要读取的文件的路径
- options 读取的选项
- callback 回调函数,将读取到的内容返回
- err 错误对象
- data 读取到的数据,会返回一个Buffer(toString()可以转换成字符串)
var fs=require("fs");
fs.readFile("hello3.txt",function(err,data){//读文件
if(!err)
//console.log(data);
fs.writeFile("hello.jpg",data,function(){//写文件
if(!err)
console.log("文件写入成功");
});
});
流式文件读取
流式文件读取也适用于一些比较大的文件,可以分多次将文件读取到内存中
var fs=require("fs");
var rs=fs.createReadStream("an.jpg");
var ws=fs.creataWriteStream("a.jpg");
rs.once("open",function(){
console.log("可读流打开");
});
rs.once("close",function(){
console.log("可读流关闭");
//数据读取完毕,关闭可写流
ws.end();
});
ws.once("open",function(){
console.log("可写流打开");
});
ws.once("close",function(){
console.log("可写流关闭");
});
//如果要读取一个可读流中的数据,必须要为可读流绑定一个data事件,data事件绑定完毕,它会自动开始读取数据
rs.on("data",function(data){
//将读取到的数据,写到可写流中
ws.write(data);
});
pipe可以将可读流中的内容,直接输出到可写流中
rs.pipe(ws);
fs模块的其他方法
var fs=require("fs");
//检查路径是否存在
//fs.existsSync(path);
var isExists=fs.existsSync("a.mp3");
//获取文件信息
//fs.stat(path,callback)
//fs.statSync(path)
// 它会给我们返回一个对象,这个对象中保存了当前对象的相关信息
fs.stat("a.mp3",function(err,stats){
console.log(stats);
//stats.isFile() 判断是不是文件
//stats.isDirectory() 判断是不是文件夹
});
//fs.unlink(path,callback);
//fs.unlinkSync(path)
//删除文件
fs.unlink("hello.txt");
//列出文件
//fs.readdir(path[,options],callback)
//fs.readdirSync(path[,options])
//读取一个目录的目录结构
//files是一个字符串数组,每一个元素就是一个文件夹或文件的名字
fs.readdir(".",function(err,files){
if(!err)
console.log(files);
});
//截断文件
//fs.truncate(path,len,callback);
//fs.truncate(path,len)
//将文件修改为指定大小
fs.truncate("hello.txt",10);
//建立目录
//fs.mkdir(path[,mode],callback)
//fs.mkdirSync(path[,mode])
fs.mkdirSync("hello");
//fs.rmdir(path,callback)
//fs.rmdirSync(path)
//删除一个目录
fs.rmdirSync("hello");
//重命名文件夹
//fs.rename(oldPath,newPath,callback)
//fs.remame(oldPath,newPath)
fs.rename("a.mp3","biji.mp3",function(err){
if(!err)
console.log("修改成功~~");
});
//fs.watchFile(filename[,options],listener)
//options传递间隔interval,options一般都是传递一个对象
//listener是回调函数,当文件发生变化时,回调函数会执行
//curr,当前文件的状态
//prev,修改前文件的状态
//这两个对象都是stats对象
fs.watchFile("hello2.txt",function(curr,prev){
console.log("文件发生了变化~~");
});