NodeJS知识点梳理-第一篇

吐槽君 分类:javascript

文章目录

        • 写在前面
        • 什么是NodeJS
        • NodeJS为什么会那么火
        • 使用NodeJS需要会的技术
        • 安装NodeJS
        • 验证安装
        • 工具使用
        • NodeJS全局变量初识
        • 认识global
        • V8引擎基本介绍
        • module介绍(node模块)
        • 事件模块(Event)
        • 文件系统 (读写 fs-FileSystem)

写在前面

废话先说好,不然你们看到后面没有耐心以后就不会看我说的废话了,为什么我要写这个node系列的文章呢?我发现现在很多公司对node的要求越来越多了,(虽然也不知道为什么吧,可能是因为他们觉得自己的公司太强大(low)了,需要一些会nodejs的人充场面吧),所以不管怎样我都觉得有必要梳理一下关于nodejs的一些知识点,我梳理的过程可能有一些不严谨的,但是基本上大体上是对的,你们尽管作为一个参考,里面涉及到的代码源码都是我自己运行以后的,所以基本没有错的,抱着对得起粉丝的态度写文章,还是要对自己的粉丝负责任的(虽然粉丝不多),最后希望看我的文章以后可以对nodejs有一个全新或者新的认识,有错误或者不严谨的地方希望各位大佬及时提出来,毕竟鄙人只是一个不那么严谨但是有态度的程序员。因为我要上班,所以只能下班以后晚上更新,慢慢更吧,emmm…废话是有点多,开始吧…

什么是NodeJS

  • Node.js是一个基本Chrome V8引擎的JavaScript运行环境
  • Node.js使用了一个事件驱动、非阻塞式I/o的模型,使其轻量又高效
  • Node.js的包管理器npm(node package mange)是全球最大的开源库生态系统

NodeJS为什么会那么火

  • 使用的是javascript
  • 速度非常的快
  • Nodejs的包管理器是全球最大的开源库
  • 可以节约资源,什么意思呢,如果我们的项目不是很大,处理的数据不是很复杂,我们使用nodejs完全是够用的,也就是说以前我们做一个有数据交互的项目需要最少两个人,一个写前端一个写后端,但是公司里面项目不是很大的话,一个会nodejs的人完全是可以胜任的,可以做一写数据库的操作。

使用NodeJS需要会的技术

  • Command Line
  • Html+css
  • javascript
  • mongo db (这个作为nosql也就是非关系型数据库,我们nodejs选择连接的是它,原因是非关系型数据库查询速度对数据的处理速度是很快的,因为没有那个表之间的各种关联,不像我们的myqsql或者oracle这样的关系型数据库,各种关联,nodejs本身就是一个处理高并发情况的语言,所以对数据操作的速度要求是很高的,这里选择的是mongo db)

安装NodeJS

  • Node
  • Node学习
  • 下载结束直接安装就可以了

验证安装

直接输入 node -v
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wJYrvSmC-1574234452713)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p28)]
输入 npm -v
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FXPQFdnz-1574234452726)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p30)]
或者我们直接运行一个我们本地的js也是一样的,直接node csdn_demo.js
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Uv5xLMb-1574234452726)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p31)]

工具使用

  • webstorm (直接下载使用,这里不写下载和安装的过程了)
  • vscode (个人建议使用这个,这个是一个比较轻量级的编辑器,重要的是你可以自己定制自己需要的插件)
  • sublime (这个是最好用的我认为,但是上手就比较难了)

NodeJS全局变量初识

  • node全局变量

举个例子

/**
 * @author clearlove
 * @aim 测试一个nodejs的全局变量
 * @param time 计时变量
 * @param timer 清除计时器
 * setTimeout  延时操作
 * setInterval 计时循环操作
 */
setTimeout(function () {
    console.info("3秒过去了,我已经执行结束了")
}, 3000)

var time = 0

let timer = setInterval(function () {
    time++
    console.info(time)
    if (time > 10) {
        clearInterval(timer)
        console.info("结束了")
    }
}, 2000)
 
  • 运行结果
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d7gci3jH-1574234452727)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p32)]

还有一点是我们常见的

console.info(__dirname)   //w文件路径名字   不不包含文件名  这个也是bnode里面的一个全局变量
console.info(__filename)  // 文件完整路径名字  
 

认识global

其实这个global和前面两个说的一样都是node里面的全局变量,但是为什么这个要单独拿出来说呢?原因自然是他有自己不一样的地方,我们都知道js里面的全局变量是windows,我们一般都是windows.一个属性,但是在node里面他的老大就是global了,那么我们直接打印出来这个看看究竟是什么

console.info(global)
 

-这里就不展示运行结果了,你们自己运行吧,太长了,截图或者直接复制都比较不友好。

V8引擎基本介绍

  • 首先说一下为什么要引擎这个东西,做什么的,我们都知道,我们的计算机时不认识我们写的什么javascript的,计算机可以识别的语言像C、C++等后端语言是可以识别的,但是他不认识我们的js,那么我们的js引擎的作用就是让计算机认识我们的js,node是C++写的,V8引擎是nodejs的核心,V8引擎其实也是C++写的。 流程就是写好的js代码通过v8引擎在node环境下运行,从而达到让计算机认识我们js语言的一个效果,简单的画一个抠脚的流程图,md文档画流程图还是比较简单(caodan)的。
  • 这里是我的理解,可能有偏差,有大佬看出问题的及时通知我,我会及时更新内容。

module介绍(node模块)

Node模块

  • 我们写代码的时候一般开发的规则是一个功能一个模块的开发,这样不仅仅是容易开发,其实更便捷的是为了以后维护等别人接收你的代码的时候不至于骂你。所以哦我们node里面其实也是一样的,每一个js都是一个模块。然后写一个总的js统一调用就可以了,我们写一个简单的例子:
  • -我们新建一个工具类的js,这个目的是为了用户输入一个数据类型,我们输出他的数据类型
/**
 * @auhor clearlove
 * @aim 判断用户输入的数据类型
 * @param {*} params 形参 
 */
var counter = function(params) {
    return typeof params
}

//将当前的工具函数导出去,变为一个任何引入的地方都可以直接使用
module.exports = counter
 

我们在node_demo.js里面我们引入他

/**
 * @author clearlove
 * @aim 接收模块的代码
 * @parms counter 将引入的js赋值给counter
 */
let counter = require("./stuff")
console.info(counter(false))
 

运行效果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l0peM4Xa-1574234452728)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p33)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IzfEePgt-1574234452729)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p34)]
在这里插入图片描述

这里介绍两个东西,第一是module.exports 第二是require

  • module.exports目的将当前的工具函数导出去,变为一个任何引入的地方都可以直接使用,这样在别的地方才可以引入
  • require,直接引入我们需要的js,为什么需要一个变量接收呢?因为不接受的话我们还是找不到引用的方法

那这个时候就有人问了,我们一个方法这样写,多个的时候怎么办呢?看例子:

  • stuff.js
/**
 * @auhor clearlove
 * @aim 判断用户输入的数据类型
 * @param {*} params 形参 
 */
var counter = function(params) {
    return typeof params
}
/**
 * 
 * @param {*} a 
 * @param {*} b 
 */
var add = function(a, b) {
    return `计算的结果是: ${a+b}`
}
/**
 * @param pi 圆周率
 */
var pi = 3.141592653589793238462643383279
    //将当前的工具函数导出去,变为一个任何引入的地方都可以直接使用
module.exports.counter = counter
module.exports.add = add
module.exports.pi = pi
 
  • node_demo.js
/**
 * @author clearlove
 * @aim 接收模块的代码
 * @parms counter 将引入的js赋值给counter
 */
let stuff = require("./stuff") //此时的stuff是一个对象
console.info(stuff.counter(false))
console.info(stuff.add(584, 654))
console.info(stuff.pi)
 
  • 运行结果
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MN4ZVwLr-1574234452730)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p35)]

这里又有人说了,那你这太麻烦了,如果一百个方法是不是你要复制一百次啊,当然不是,我们可以直接将一个对象导出去,看代码:

    /**
     * 将每一个方法名字均导出去
     */
module.exports = {
    counter: counter,
    add: add,
    pi: pi
}
 
  • 这里就不展示运行结果了,和上面的是一样的。还有就是你上面对象的值写你的方法也是可以的,看代码:
        /**
         * @param pi 圆周率
         */
    var pi = 3.141592653589793238462643383279
        /**
         * 将每一个方法名字均导出去
         */
    module.exports = {
        counter: function(params) {
            return typeof params
        },
        add: function(a, b) {
            return `您计算的结果是:${a + b}`
        },
        pi: pi
    }
 

这里需要解释一下上面有一句话是这样的:return 计算的结果是: ${a+b}那么这句话是es6的一个写法,就黑我们平常写+拼接是一个意思,只是这样写是一个比较非常规的写法而已。

事件模块(Event)

Node事件

  • 事件我们在js里面也是经常遇到的,譬如鼠标点击、键盘事件等等,事件是为了解决交互问题,那么node里面也是有事件模块的,他就是我们这里要说的Event
    需要注意的三点:
    1、大多数的Nodejs核心API都是采用惯用的异步事件驱动架构的(fs/http)
    2、所有能触发事件的对象都是EventEmitter类的实例
    3、事件的流程是:引入模块->创建EventEmitter对象->注册事件->触发事件
  • 看例子
/**
 * @author clearlove
 * @aim 演示基本的事件使用的过程
 * @param myEmitter 创建eventemitter对象
 */
//引入事件模块  import event from 'events' 和下面的写法是一样的,只是这个是es6的写法
var event = require('events');
//创建eventemitter对象
var myEmitter = new event.EventEmitter();
//注册一个事件  (这里解释一下什么是注册一个事件,我们使用jquery的时候会知道,我们想使用一个事件的时候我们是元素之前就创建好的 例如:Element.on('click',function (params) {}))
myEmitter.on('anyevent',function(param){
    console.info(typeof param)
    //return typeof param
})
//触发事件 你可以直接调用这个事件 当然也可以传递参数
//myEmitter.emit('anyevent',false) //前者是事件名字,后者是参数
myEmitter.emit('anyevent',false)
 

运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YZYfMQJo-1574234452731)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p36)]

  • 处理异步执行的情况:
    看代码:
/**
 * @author clearlove
 * @aim 演示异步使用
 * @param myEmitter 创建eventemitter对象
 */
var event = require('events');
var myEmitter = new event.EventEmitter();
myEmitter.on('anyevent',function(param){
    console.info(param)
})
myEmitter.emit('anyevent','我是myEmitter事件')
console.info('我被执行了,在myEmitter事件之后')
 

运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-beKR2950-1574234452731)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p37)]

可以看到我们的代码是顺序执行的,也就是说上面声明的事件执行结束以后下面的事件才开始执行的,那么这个时候我想翻过来执行的顺序怎么办呢?Node官方给出的解决办法是这样的,看代码:

/**
 * @author clearlove
 * @aim 演示异步使用
 * @param myEmitter 创建eventemitter对象
 */
var event = require('events');
var myEmitter = new event.EventEmitter();
myEmitter.on('anyevent',function(param){
    //EventEmitter 会按照监听器注册的顺序同步地调用所有监听器。 所以必须确保事件的排序正确,且避免竞态条件。 可以使用 setImmediate() 或 process.nextTick() 切换到异步模式
    setImmediate(()=>{
        console.info(param)
    })
})
myEmitter.emit('anyevent','我是myEmitter事件')
console.info('我被执行了,在myEmitter事件之前')
 

运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qn4ThIjX-1574234452732)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p38)]

具体下面还有什么once、error或者别的什么方法这里就不写了,都是如出一辙,会了一个就可以了。
多个参数的情况处理,看代码:

/**
 * @author clearlove
 * @aim 演示多参数
 * @param myEmitter 创建eventemitter对象
 */
var event = require('events');
var myEmitter = new event.EventEmitter();
myEmitter.on('event', (a, b) => {
    console.log(a + b,this);
  });
  myEmitter.emit('event', 1, 2);
 

运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FA6pO5rg-1574234452733)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p39)]

当监听器被调用时,this指向的是EventEmitter对象

文件系统 (读写 fs-FileSystem)

  • 文件系统一般我们用到的都是一些读取、写入、别的一般很少会用到,node里面读取和写入文件也是一样的。
- 读取文件 (fs.readFile)
- 写入文件 (fs.writeFile)
- 流程:引入fs模块->调用方法->异常捕获
 
  • 同步读写文件
/**
 * @author clearlove
 * @aim 演示文件读写
 * @param myEmitter 创建eventemitter对象
 */
//引入fs
var fs = require('fs'); 
//通过对象调方法     同步读取文件
var readme = fs.readFileSync('readMe.txt','utf-8');
console.info(readme)
fs.writeFileSync('writeMe.txt',readme)  //同步写入文件  
 

运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iuXLQue7-1574234452733)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p40)]
会发现写入文件的时候下面会多出一个我们刚刚写的文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xK2QKb4V-1574234452734)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p41)]

  • 异步读写文件
    看代码:
/**
 * @author clearlove
 * @aim 演示文件读写
 */
//引入fs
var fs = require('fs');  
/**
 * @readMe.txt 需要读的文件
 * @utf-8 读的字符格式
 * @error 抛出异常
 * @data 读的内容
 */
fs.readFile(__filename,'utf-8', function (error,data) {
    if(error) throw error
    //在我们读取结束后将自身的内容写入到新的文件中去
    writeMeSync(data)
})
/**
 * @writeMeSync 写入一个文件
 * @param {*} 写入的参数 
 */
function writeMeSync(params) {
    fs.writeFile('SyncWriteMe.txt',params,function(error,data){
    if(error) throw error
})
}
 

-运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fHqGp2fG-1574234452735)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p44)]

  • 创建文件和删除文件
 - 创建文件夹 fs.mkdir
 - 删除文件夹 fs.rmdir
 - 删除文件 fs.unlink
 流程:引入fs模块->调用方法->异常捕获
 

看代码:

/**
* @author clearlove
* @aim 演示删除文件以及文件夹
*/
//引入fs
var fs = require('fs'); 
fs.unlink('SyncWriteMe.txt',function (err) {
   if (err) throw err
   console.info('删除成功')
})
//创建文件夹
fs.mkdirSync('views',function(err){
   if (err) throw err
   console.info('创建成功')
})
//删除文件夹
fs.rmdirSync('views',function(err){
   if (err) throw err
   console.info('删除成功')
})
 
  • 你们自己运行吧
  • 异步删除文件
/**
 * @author clearlove
 * @aim 演示删除文件以及文件夹
 */
//引入fs
var fs = require('fs');
//异步操作文件夹   新建一个文件夹,读当前文件内容,将最新的文件内容写到一个新的文件里面
fs.mkdir('views', function () {
    fs.readFile(__filename, 'utf-8', function (err, data) {
        if (err) throw err;
        fs.writeFile('./views/new.js', data,function(err){
           if(err) throw err
            console.info('创建成功')
        })
    })
})

//异步删除文件夹 删除文件夹的前提是文件夹是空的,所以我们第一步是将文件夹里面的文件删除,成功以后删除文件夹
fs.unlink('./views/new.js',function (err) {
    if(err) throw err
    fs.mkdir('vires',function (err,data) {
        if(err) throw err
        console.info('文件夹删除成功')
    })
})
 
  • 运行结果:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-La0F2vjq-1574234452735)(evernotecid://72A0867B-C2C9-4394-90F0-D1AD032DA4AC/appyinxiangcom/24072006/ENResource/p45)]

ok,先写到这里吧,NodeJS还有很多需要学的,但是做事情不可以一蹴而就,循序渐进的来吧,下篇文章有时间的时候写一下剩下的一些关于NodeJS的知识,因为我是自学的,所以写的一些不规范或者有问题的地方可以提出来,我直接改掉,学习NodeJS注定是一条漫长的路,下一篇文章我会写一下本地怎么跑一个服务,将本地的html渲染出来,同时写一下关于buffer和stoream流的概念,共勉,感谢。

回复

我来回复
  • 暂无回复内容