前言:
今天我们开始nodejs的基本学习,Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。Node.js 的包管理器 npm,是全球最大的开源库生态系统。
环境配置:
首先我们配置nodejs的环境,打开官网
选择一个安装包下载即可
然后一直点下一步,傻瓜操作,就可以安装成功了
它会自动配置环境路径,我们可以在cmd下验证是否安装成功
然后我们去安装一个很出名的编辑器——VS code
它和VS是两码事,都是微软公司的产品,但是用法是不一样:
1、vs:Visual Studio是一个集成的开发环境,相对来说比较完整,它包括了整个软件生命周期中所需要的大部分工具,如UML工具、代码管控工具、集成开发环境(IDE)等等。
如果初学编程(控制台)用vs,cocos2dx开发游戏也是用vs。
2、vs code:是一款免费开源的现代化轻量级代码编辑器,支持几乎所有主流的开发语言的语法高亮、智能代码补全、自定义热键、括号匹配、代码片段、代码对比 Diff、GIT 等特性,支持插件扩展,并针对网页开发和云端应用开发做了优化。
在官网就可以安装VSnode,然后跟着这个网站实现汉化
然后我们在vsCode里安装一个插件——Terminal
它可以打开一个终端,可以方便我们查看命令的效果
基本环境就OK了,老规矩,学习一门新语言,先 hello world 一下
console.log("Hello World!");
Terminal输出:
PS F:\nodeJS的平时作品\helloNode> node app.js
Hello World!
基本语法:
全局对象:
JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。
在浏览器 JavaScript 中,通常 window 是全局对象, 而 Node.js 中的全局对象是 global,所有全局变量(除了 global 本身以外)都是 global 对象的属性。
在 Node.js 我们可以直接访问到 global 的属性,而不需要在应用中包含它。
例如上面示例的console
就是一个全局对象
再比如:
setTimeout(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb)。:setTimeout() 只执行一次指定函数。
返回一个代表定时器的句柄值。
setTimeout(()=>{
console.log("请等三秒");
},3000)
三秒后输出了“请等三秒”
箭头函数=>是ES6语法,正常写法是这样
setTimeout(function(){
console.log("请等三秒");
},3000);
另外还有例如:
setInterval(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb)。
返回一个代表定时器的句柄值。可以使用 clearInterval(t) 函数来清除定时器。
setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。
setInterval(function(){
console.log("每秒重复输出我");
},1000);
结果就会每秒都重复输出,按下Ctrl+C停止
还可以尝试一个
var time=0;
var timer=setInterval(function(){
time+=2;
console.log(time+"秒已经过去")
if(time>5)
{
clearInterval(timer);
}
},2000);
输出“2、4、6秒已经过去”后就不再输出了
全局对象更多内容可以查看这里
函数表达式:
普遍函数定义:
函数定义非常简单:
function hashBlog(){
console.log('wayneblog.top');
}
hashBlog();
输出:wayneblog.top
函数表达式:
变量保存对函数的引用
var hashBlog=function(){ //匿名函数
console.log('wayneblog.top');
}
hashBlog();
输出:wayneblog.top
回调函数:
回调函数概念:
1、回调函数是作为参数传递给另一个函数
2、回调函数是一段可执行的代码段,它作为一个参数传递给其他的代码,其作用是在需要的时候方便调用这段(回调函数)代码
3、 函数运行完成,再执行回调函数
回调函数特点:
1、不会立刻执行
回调函数作为参数传递给一个函数的时候,传递的只是函数的定义并不会立即执行。
2、是个闭包
回调函数是一个闭包,也就是说它能访问到其外层定义的变量。
3、执行前类型判断
在执行回调函数前最好确认其是一个函数。
function callFunction(fun){
fun();
}
var hashBlog=function(){ //匿名函数
console.log('wayneblog.top');
}
callFunction(hashBlog);
输出:wayneblog.top
加参数:
function callFunction(fun,who){
fun(who);
}
var hashBlog=function(who){ //匿名函数
console.log('wayneblog.top'+who);
}
callFunction(hashBlog,"网站");
输出:wayneblog.top网站
模块:
为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。
模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展。
Node.js 提供了 exports 和 require 两个对象,其中 exports 是模块公开的接口,require 用于从外部获取一个模块的接口,即所获取模块的 exports 对象。
示例:
我们新建两个文件
#main.js
var counter=function(arr){
return "这里有一个长度为"+arr.length+"的数组"
}
module.exports=counter;
#app.js
var counter=require('./main.js');
console.log(counter(['superman','woderwoman','batman']));
然后node app,就会输出:这里有一个长度为3的数组
exports暴露多个属性,即暴露一个对象有多个建
#main.js
var counter=function(arr){
return "这里有一个长度为"+arr.length+"的数组"
}
//return后面是`符号引注字符串,不是单引号
//这时一个ES6的模板字符串写法
//直接就是a+b的结果
var adder=function(a,b){
return `两个数字相加之和为 ${a+b}`;
}
var PI=3.14;
//暴露的是一个对象
//对象有三个键(对用右边三个值)
module.exports.counter=counter;
module.exports.adder=adder;
module.exports.PI=PI;
#app.js
//接收一个对象
var stuff=require('./main.js');
console.log(stuff.counter(['superman','woderwoman','batman']));
console.log(stuff.adder(5,7));
console.log(stuff.PI);
这里有一个长度为3的数组
两个数字相加之和为 12
3.14
上面的main.js中可以直接简写export模块公开如下(更是有键值对应的感觉了)
module.exports={
counter:counter,
adder:adder,
PI:PI
}
也可以直接用匿名函数作为值,这里就不写了
事件:
大多数 Node.js 核心 API 构建于惯用的异步事件驱动架构,其中某些类型的对象(又称触发器,Emitter)会触发命名事件来调用函数(又称监听器,Listener)。
例如,net.Server
会在每次有新连接时触发事件,fs.ReadStream
会在打开文件时触发事件,stream会在数据可读时触发事件。
所有能触发事件的对象都是 EventEmitter
类的实例。 这些对象有一个 eventEmitter.on()
函数,用于将一个或多个函数绑定到命名事件上。 事件的命名通常是驼峰式的字符串,但也可以使用任何有效的 JavaScript 属性键。。
当 EventEmitter
对象触发一个事件时,所有绑定在该事件上的函数都会被同步地调用。 被调用的监听器返回的任何值都将会被忽略并丢弃。
示例:
//events是一个核心库
var events=require('events');
//新增一个EventEmitter实例(EventEmitter是个类)
var myEmitter=new events.EventEmitter();
//EventEmitter实例绑定了一个事件
//名称是someEvent,发生之后调用后面那个回调函数
myEmitter.on('someEvent',function(message){
console.log(message);
})
//用emit触发事件,传入后面为参数
//绑定在该事件上的所有函数会被同步调用
myEmitter.emit('someEvent','事件被触发');
输出:事件被触发
我们再来看一个大例子:
var events=require('events');
//导入util核心库
//util是一个工具库
var util=require('util');
//javascript中定义类的写法
var Person=function(name){
this.name=name;
}
//该方法表明继承关系,让person继承EventEmitter
util.inherits(Person,events.EventEmitter);
//实例三个对象
var xiaoming=new Person('xiaoming');
var lili=new Person('lili');
var lucy=new Person('lucy');
var person=[xiaoming,lili,lucy];
person.forEach(function(person){
person.on('speak',function(message){
console.log(person.name+'said:'+message);
})
})
xiaoming.emit('speak','我是小明');
lucy.emit('speak','我是路西');
输出:
xiaomingsaid:我是小明
lucysaid:我是路西
读写文件:
同步读取文件:
#test.txt
这里是text.txt,是一个用于测试的文本文件
#main.js
//导入核心库(文件系统)
var fs=require('fs');
//读取文件内容
//同步读取函数readFileSync,utf8:编码集
var test=fs.readFileSync("test.txt","utf8");
console.log(test);
输出:
这里是text.txt,是一个用于测试的文本文件
同步写入文件:
#main.js
//导入核心库(文件系统)
var fs=require('fs');
//同步写入函数writeFileSync,
var test=fs.writeFileSync("test.txt","这是第二个测试文件");
#test.txt
原本的内容改变成了:
这是第二个测试文件
同步操作(sync)会将命令从上到下依次执行,如果有阻塞就会一直卡到那一步(nodejs在执行javascripts的时候是单线程的)
异步读取文件:
#test.txt
这里是text.txt,是一个用于测试的文本文件
#main.js
//导入核心库(文件系统)
var fs=require('fs');
//读取文件内容
//异步读取函数readFile,utf8:编码集
//后面是一个回调函数,err是错误信息,data就是test的文件内容
var test=fs.readFile("test.txt","utf8",function(err,data){
if(err){
console.log(err);
}else{
console.log(data);
}
});
console.log("我是最后一句命令");
输出:
我是最后一句命令
这里是text.txt,是一个用于测试的文本文件
可以看到,“最后一句命令”尽然先输出了,这就是一个异步读取文件
内部操作:
nodejs维护了一个事件队列,首先执行var fs=require(‘fs’),然后执行第二条命令var test=fs.readFile(……)的时候,会注册一个事件,告诉这个事件队列它将要去读一个文件(但是此时没有执行后面的回调函数),然后在执行主线程的第三个语句console.log(“我是最后一句命令”),当主线程控线之后,他就会去找事件队列里的事件,把它取出来,再从线程池中发起一个线程,去执行这事件队列里面的事件,执行成功之后,它再告诉主线程它已经成功了,主线程再把数据取出。
这就是nodejs高性能的原因,它每一个方法是异步的
异步写入文件:
#main.js
//导入核心库(文件系统)
var fs=require('fs');
//异步写文件
fs.writeFile('test.txt', '异步写入文件', function(err){
if(err)
console.log(err);
else
console.log('写文件操作成功');
})
console.log("我是最后一句命令");
#test.txt
异步写入文件
创建和删除目录:
异步删除文件:
#main.js
//导入核心库(文件系统)
var fs=require('fs');
fs.unlink("test.txt",function(){
console.log("已经删除文件");
})
同步删除文件:
#main.js
//导入核心库(文件系统)
var fs=require('fs');
fs.unlinkSync("test.txt")
同步创建目录:
//导入核心库(文件系统)
var fs=require('fs');
fs.mkdirSync('DIR');
同步删除目录:
//导入核心库(文件系统)
var fs=require('fs');
fs.rmdirSync('DIR');
fs的rmdir或者rmdirSync方法只能对空文件夹
异步创建目录:
//导入核心库(文件系统)
var fs=require('fs');
fs.mkdir('DIR',function(err){
if(err){
console.log(err);
return false;
}
console.log('创建目录成功');
})
创建了DIR目录
新建目录且新建文件示例:
//导入核心库(文件系统)
var fs=require('fs');
fs.mkdir('DIR',function(err){
if(err){
console.log(err);
}
else{
console.log('创建目录成功');
fs.writeFile('./DIR/test.txt','异步文件',function(err){
if(err){
console.log(err);
}
else{
console.log("创建文件成功");
}
})
}
})
流和管道:
流:
流(stream)是 Node.js 中处理流式数据的抽象接口。 stream
模块用于构建实现了流接口的对象。
Node.js 提供了多种流对象。 例如,HTTP 服务器的请求和 process.stdout
都是流的实例。
流可以是可读的、可写的、或者可读可写的。 所有的流都是 EventEmitter
的实例。
流的应用:
- 处理数据,最典型的就是http服务的时候.请求和响应就是流的一种体现,再比如对数据进行的处理,例如webpack,gulp也大量运用了流这个技术,或者对文件进行打包压缩
- 提高读写性能,与文件系统的读写命令有所区别,文件系统的读写文件命令是一次性把文件里的内容放到内存当中,如果文件很大,用这种命令就不太合适,要用流来处理,流会把内容放到buffer(缓存)中,一边放一边处理,这样的话性能就会很高
示例:
#test.txt
在故事开始时,王后坐在……
#main.js
//导入核心库(文件系统)
var fs=require('fs');
//__dirname是一个全局变量,代表当前目录
//createReadStream表示创建一个读的流(输入流)
var ReadStream=fs.createReadStream(__dirname+'/test.txt','utf8');
var data=""
//流是一个事件的示例,具有一些事件的特性
//例如绑定监听函数
//data事件是当有数据可读时触发
ReadStream.on('data',function(chunk){
data+=chunk;
})
//end事件是接收数据完成之后触发
ReadStream.on('end',function(){
console.log(data)
})
输出
在故事开始时,王后坐在……
ReadStream.setEncoding('utf8')//编码也可以这样写
而创建写入流写入内容也很简单:
//导入核心库(文件系统)
var fs=require('fs');
//__dirname是一个全局变量,代表当前目录
//createWriteStream创建一个写的流(输出流)
var WriteStream=fs.createWriteStream(__dirname+'/test2.txt')
//编辑流出内容
var WriteData="小女孩穿着红舞鞋跳舞跳了一天!";
//流出
WriteStream.write(WriteData);
WriteStream.end();
//结束的监听方法
WriteStream.on('finish',function(){
console.log('创建成功');
})
管道:
var myReadStream = fs.createReadStream(__dirname + '/readMe.txt')
var myWriteStream = fs.createWriteStream(__dirname+'/writeMe2.txt')
myReadStream.pipe(myWriteStream)
利用管道,直接复制出一个新文件
nodejs的第一部分就先记录到这里,有新的知识我会不断补充。
商业转载 请联系作者获得授权,非商业转载 请标明出处,谢谢