使用node的REPL模式
REPL(Read-eval-print loop)输入-求值-输出循环
进入的方式就是 命令行 下进入 输入node进入REPL模式
建立HTTP服务器
node.js是为网络而诞生的平台,node.js将“http服务器”这一层抽离,直接面向浏览器用户
使用node.js建立htpp服务器
var http=require('http'); http.createServer(function(req,res){ res.writeHead(200,{'contet-Type':'text/html'}); res.write("<h1>jiasjia</h1>"); res.end('<p>jiasjia</p>'); }).listen(3000); console.log("http server is listing at port 3000")在浏览器输入local:3030
页面上会显示
jiasjia
jiasjia
程序运行的原理:
对所有http请求答复同样的内容并监听了3000端口,在终端运行这个脚本时,我们会发现它并不像hello Word一样结束后立即退出,而是一直等待,知道按下ctrl+c才会结束
使用supervisor
node.js只有在第一次引用到某部分时才会去解析脚本文件,以后都会直接访问内存,避免重复载入,这种方式有利于提高性能,却不利于开发,因此,我们在开发过程中总是希望修改后就看到效果,而不是每次都得终止进程并重启这就是supervisor的作用
npm install -g supervisor
安装了以后当代码被改动时,运行的脚本会被终止,然后重新启动
异步时I/O与事件式编程
node.js最大的特点就是异步时I/O与事件紧密结合的编程模式,这种这种模式下控制流很大程度上要依靠事件和回掉函数来组织,一个逻辑单元拆分为若干单元
1、阻塞与线程
同步式i/o:线程在执行中如果遇到磁盘读写或网络通信(I/O)操作,通常都需要消耗较长的时间,这时操作系统会剥夺这个线程的cpu执行权,使其暂停执行,同时资源会让给其他的工作线程。这就是阻塞的式i/o
异步式i/o:则针对所有I/O操作不采用阻塞的策略。当线程遇到I/O操作时,不会以阻塞的方式等待I/O操作完成或数据的返回,而是将I/O请求发送给骚做系统,继续执行下一条语句。当操作系统完成I/O操作时,以事件的形式通知I/O操作的线程,线程会在特定的时候处理这个事件,为了处理异步I/O,线程必须有事件循环,不断的检查有没有未处理的事件
2、回调函数
会输出var fs=require('fs'); function aa(err,data){ if(err){ console.log(err); } else{ console.log(data) } } fs.readFile('file.txt','utf-8',aa); console.log('end.')
end.
文件里边的内容
与料想的会先输出文本里边的内容不一样,而是先输出了end.
这里aa就是一个回调函数,在readFile调用时所做的工作就是把I/O请求发送给操作系统,然后立即执行跟后面语句,执行完了以后进入事件监听环节,当fs收到I/o请求完成的事件时,事件循环会主动调用回调函数以完成后续的工作,这就是为什么我门先看到end,后看到文件中的内容的原因
3、事件
node.js所有的异步I/O操作在完成时都会发送一个事件到事件队列,事件由EventEmitter对象提供的。
var EventEmitter=require('events').EventEmitter; var event=new EventEmitter(); event.on('some_event',function(){ console.log('some_event occurd'); }); setTimeout(function(){ event.emit('some_event'); },1000)运行的结果在控制台隔了一秒之后 输出some_event occured
原理:event对象注册了事件some_event的一个监听器,setTimeout在1秒以后向event对象发送事件some_event 此时就会执行some_event中的内容
4、模块和包
模块(module)和包(Package)是node.js的重要支柱,开发一个具有一定规模的程序不可能只使用一个文件,通常把各个功能拆分、封装、组合起来,模块就是为了实现这种方式而诞生的。node.js提供了require函数来实现来调用其它模块,而且模块都是基于文件的
什么是模块?
模块是Node.js应用程序的基本组成成分,文件和模块是一一对应的
创建模块
创建模块:node.js提供了exports和require两个对象,exports是模块公开的接口,require用于从外部获取一个模块的接口,也就是获取该模块的exports
自定义一个模块 first.js
var name; exports.setName=function(thyName){ name=thyName; }; exports.sayHello=function(){ console.log(name); }getFirst.js使用first.js
var myModule=require('./first'); myModule.setName('skao'); myModule.sayHello();node getFirst.js会输出skao
node的单次加载
上述实例类似于创建了一个对象,但是实际上与对象有本质上的区别因为require不会重复加载,也就是无论调用多少次require,获得的模块都是同一个
var myModule=require('./first'); myModule.setName('skao'); var myModule1=require('./first'); myModule1.setName('new'); myModule.sayHello();发现输出的是new 这是因为myModule1和myModule2这两个变量指向的是同一个实例,2的name会把1的name覆盖掉
实现封装
封装了一个Hello的类
function Hello(){ var Name; this.setName=function(nn){ Name=nn; } this.hello=function(){ console.log(Name); } }; module.exports=Hello;这时接口对象输出的就是Hello对象本身,而不是原来的exports
使用的方法
var myModule=require('./first'); myModule=new myModule(); myModule.setName('sasa'); myModule.hello();创建包
包是模块基础上更深一步的抽象,node.js的包类似于c/c++的函数库或者java的类库。它将每个独立的功能封装起来,用于发布、更新、依赖和版本控制。
node.js的包是一个目录,其中包括json格式的包说明文件package.json。
1、作为文件夹的模块
新建一个文件夹somepackage里边包含一个文件index.js里边的内容
exports.hello=function(){ console.log('hello'); }在文件夹的外边新建一个文件getpackage.js
var somePackage=require('./somepackage'); somePackage.hello();控制台输出 hello
2、package.json 在somepackage文件夹下
在package.json中写
{
"main":"./lib/interface.js"
}
运行getpackage.js依然会得到结果,这是因为在调用某个包时,会首先检查包中package.json文件的main字段将其作为包的接口模块,如果没有会尝试找index.js
或者index.node作为包的接口
package.json应该要包含以下字段
node.js的包的管理器
npm install express
在使用npm安装包的时候,有两种模式本地模式和全局模式
一般来说安装的时候都使用到全局模式,因为许多程序都有可能用到它,为了减少副本而使用了全局模式,全局模式会注册path环境变量
全局对象
全局变量的属性可以在程序的任何地方访问,浏览器的window对象,Node.js中的全局对象就是global,所有全局变量都是global对象的属性
比如console process
process
process是一个全局变量,即golbal对象的属性,它用于描述当前Node.js进程状态的对象,提供了一个与操作系统的简单的接口
node argv.js
输出[ 'node', 'D:\\work\\nodeWorkspace\\argv.js' ]
node argv.js 1991 name=byvoid --v 'Carbo Kuo'
输出
[ 'node',
'D:\\work\\nodeWorkspace\\argv.js',
'1991',
'name=byvoid',
'--v',
'\'Carbo',
'Kuo\'' ]
在argv.js里边写
process.stdout.write('sasasa');
会输出sasasa
process.stdin.resume(); process.stdin.on('data',function(data){ process.stdout.write('read form console'+data.toString()); })控制输入什么就会输出什么
node.js进程只有一个线程,node.js适合i/o密集型的应用而不是计算密集型的应用,在任何时刻都只有一件事在进行,node.js的一个编程原则就是尽量缩短每个事件的执行时间,这个方法就是把一个复杂的工作拆散
console
console.log()
console.error() 向标准错误流输出
console.trace() 向标准错误刘输出当前调用栈
常用工具util
1、util.inherits
实现对象间原型继承的函数,javascript没有提供对象继承语言级别特性,而是通过原型复制来实现的
var util=require('util'); function Base(){ this.name='base'; this.base=1991; this.sayhello=function(){ console.log(this.name); } } Base.prototype.showName=function(){ console.log(this.name); } function Sub(){ this.name='sub'; } util.inherits(Sub,Base); //sub继承了Base类的属性和方法 var ob=new Base(); ob.sayhello(); //base ob.showName(); //base var os=new Sub(); os.showName(); //sub os.showName(); //sub console.log(os);注意:Sub仅仅继承的了在原型中的定义的函数,而构造函数内部创造的base属性和其他在构造函数声明的方法都不会被继承
2、util.inspect
这个方法是将任意一个对象转换为字符串的方法,一般用来调试,至少要接受一个参数object(要转换的对象)
var util=require('util'); function Person(){ this.name='bb'; this.toString=function(){ return this.name; } } var obj=new Person(); console.log(util.inspect(obj)); console.log(util.inspect(obj,true));运行结果
{ name: 'bb', toString: [Function] }
{ name: 'bb',
toString:
{ [Function]
[length]: 0,
[name]: '',
[arguments]: null,
[caller]: null,
[prototype]: { [constructor]: [Circular] } } }
事件驱动events
events模块是node.j最重要的模块,原因是node本省架构就是事件式的,就是events提供了接口。events模块不仅用于用户代码与Node.js下层事件循环的交互,还几乎被所有的模块依赖
1、事件发生器
events模块只提供了一个对象:events.EventEmitter。EventEmitter的核心就是事件发射与事件监听器功能的封装。EventEmitter的每个事件由一个事件和若干个参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter支持若干个事件监听器。当事件发射时,注册到这个事件的监听器就被依次调用,事件参数作为回调函数来处理
var eventem=require('events').EventEmitter; var events=new eventem(); events.on('some_events',function(aa,bb){ console.log('listener1',aa,bb); }) events.on('some_events',function(aa,bb){ console.log('listener2',aa,bb); }) events.emit('some_events','bb','1221');给some_event注册了两个事件
会输出
listener1 bb 1221
listener2 bb 1221
EventEmitter常用的API
1、EventEmitter.on(event,listener)为指定事件注册一个监听器。接受一个字符串event和一个回调函数listener
2、EventEmitter.emit(event,[参数1],[参数2])发射event事件,传递若干可选参数到事件监听器的参数表
3、EventEmitter.once(event,listener)为指定事件注册一个单次监听器,监听器最多只能触发一次,触发后立刻解除该监听器
4、EventEmitter.removeListener(event,listener)移除指定事件的摸个监听器
var eventem=require('events').EventEmitter; var events=new eventem(); function cc(aa,bb){ console.log('listener1',aa,bb); } events.on('some_events',cc); events.removeListener('some_events',cc); events.on('some_events',function(aa,bb){ console.log('listener2',aa,bb); }) events.emit('some_events','bb','1221');运行程序只会输出一次 listener1 bb 1221
5、EventEmitter.removeAllListener([event])移除所有事件的监听器
var eventem=require('events').EventEmitter; var events=new eventem(); function cc(aa,bb){ console.log('listener1',aa,bb); } events.on('some_events',cc); events.on('some_events',function(aa,bb){ console.log('listener2',aa,bb); }) events.removeAllListeners('some_events'); events.emit('some_events','bb','1221');运行程序不会输出任何的信息
2、error事件
EventEmitter定义了一个特殊的事件error,它包含了“错误”的语义,我们在遇到异常通常会发射error事件。当error被发射时,EventEmitter规定如果没有响应的监听器,node.js会把它当作异常,退出程序并打印调用栈。我们一般要为发射error事件的对象设置监听器,避免碰到错误后整个程序崩溃
当这样使用的时候就会使程序崩溃
var eventem=require('events').EventEmitter; var events=new eventem(); events.emit('error');3、继承EventEmitter
大多数的时候我们不会直接使用EventEmitter对象,而是在对象中继承他。包括fs、net、http在内的,只要支持事件响应的核心模块都是EventEmitter的子类
文件系统fs
fs模块是对文件操作的封装、提供了文件的读取、写入、更名、删除、遍历目录、连接等POSIX文件系统操作,与其他模块不同的是fs模块中所有的操作提供了异步的和同步的两个版本
1、fs.readFile
fs.readFile(filename,[encoding],[callback(err,data)])是最简单的读取文件的函数,他必须接受一个必选参数,表示要读读取的文件名。
参数encoding是可选的,
参数callback的两个参数err,data err表示有没有错误发生 data是文件内容
如果指定了encoding,data是一个解析后的字符串,否则data将会是以Buffer形式表示的二进制数据
var fs=require('fs'); fs.readFile("file.txt",'utf-8',function(err,data){ if(err){ console.log(err); } else{ console.log(data); } });会输出 文件中的内容:赵文娟
2、fs.readFileSync
参数列表和fs.readFile是一致的,但是它是fs.readFile的同步的版本,读取到的内容会以函数的返回值的形式返回。
var fs = require('fs'); var contentText = fs.readFileSync('file.txt','utf-8'); console.log(contentText);3、fs.open
fs.open(path,flags,[model],[callback(err,data)])path为文件的路径,flags可以是以下值
4、fs.read
fs.read(fd,buffer,offset,length,position,[callback(err,bytes,buffer)])是read函数的封装,相比fs.readFile提供了更底层的接口。
fs.read的功能是从指定的文件描述符fd中读取数据并写入buffer指向的缓冲区对象。offset是buffer的写入偏移量。
length是要从文件中读取的字节数
position是文件读取的起始位置,如果position的值为null,则从开始读
回调函数的 bytesRead和buffer分别表示字节数和缓冲区对象
var fs = require('fs'); fs.open('file.txt','r',function(err,fd){ if(err){ console.log(err); return ; } var buf=new Buffer(8); fs.read(fd,buf,0,8,null,function(err,bytesRead,buffer){ if(err){ console.log(err); return ; } console.log('bytesRead'+bytesRead); //读取的字节数 console.log(buffer); //输出缓冲区 }) })HTTP服务器与客户端
node.js标准库提供了http模块,其中封装了一个高效的HTTP服务器和一个简易的HTTP客户端。http.server是一个基于事件的HTTP服务器,它的核心由Node,js下层的c++部分实现,接口由javaScript实现
1、http服务器
http.server是http模块中的服务器对象,用Node.js做的所有基于HTTP协议的系统、网站、社交应用甚至代理服务器,都是基于http.server实现的。
http.Server的是一个基于事件的http服务器,所有的请求都被封装为独立的事件,开发者只需要对它的事件编写响应函数即可实现HTTP服务器的所有功能。继承自EventEmitter,提供了以下几个事件。
request:当客户请求到来时,该事件被触发,提供两个参数req和res,分别是http.SeverRequest和http.ServerResponse的实例。表示请求和响应的消息
connection:当TCP连接建立时,该事件被触发,提供了一个参数socket,为net.socket的实例。connection事件的粒度大于request,因为客户端在Keep-Alive模式下可能在同一个连接内发送多次请求
close:当服务器关闭时,该事件被触发