目录

nodejs

环境变量

  1. 当我们在命令行窗口打开一个文件或调用一个程序时,系统会首先在当前目录下寻找文件程序,如果找到了直接打开,如果没找到会依次到环境变量path的路径中寻找,否则报错,类似于作用域链。
  2. 将一些经常需要访问的程序和文件的路径添加到path中,这样我们就可以在任意位置来访问这些文件和程序了。

进程和线程

进程

  1. 负责为程序的运行提供必备的环境
  2. 进程就相当于工厂中的车间

线程

  1. 线程计算机中的最小的计算单位,线程负责执行进程中的程序
  2. 线程相当于工厂中的工人

单线程

  1. js是单线程

多线程

node简介

  1. 能够在服务器端运行的JavaScript环境
  2. 处理不了并发量过高的情况,基于web的轻量级应用
  3. node是单线程,处理速度很快,对服务器硬件要求低。但是处理不了过多的用户,此时只能用分布式。

node基础

模块化

  1. 在node中,一个js文件就是一个模块

  2. 在node中,通过require()函数来引入外部的模块,require()可以传递一个文件的路径作为参数,node将会自动根据该路径来引入外部模块

  3. 使用require()引入模块以后,该函数会返回一个对象,这个对象代表的是引入的模块

  4. 在node中,每一个js文件中的js代码都是独立运行在一个函数中的function(){},在全局里看不到,所以一个模块中的变量和函数在其他模块中无法访问

  5. 在node中向外部暴露属性或方法,用exports,将需要暴露给外部的变量或方法设置为exports的属性即可

    1
    2
    3
    4
    
    exports.x = "我是02.module.js中的x"
    exports.add = function(a,b){
        return a+b
    }
    

模块标识

  1. 使用require()引入外部模块时,使用的就是==模块标识==,我们可以通过模块标识来找到指定的模块

核心模块

  1. 由node引擎提供的模块

  2. 核心模块的标识就是模块的名字

    1
    
    var fs = require("fs")
    

文件模块

  1. 由用户自己创建的模块
  2. 文件模块的标识就是文件的路径(绝对,相对)

全局对象

  1. global,它的作用和window类似

  2. 在全局中创建的变量都会作为global的属性保存

  3. 在全局中创建的函数都会作为global方法保存

    1
    2
    
    {a = 10
    log(global.a)}//argunments.callee当前执行的函数对象
    
  4. node在执行模块中的代码时,它会在代码的最顶部,添加function(exports,require,module,_filename,_dirname){

    在代码的最底部,添加如下代码 }

  5. 实际上模块中的代码都是包装在一个函数中执行的,并且在函数执行时,同时传递进了5个实参

    实参
    exports 该对象用于将变量或函数暴露到外部
    require 函数,用来引入外部的模块
    module 代表的是当前模块自身,exports就是module的属性,可以使用exports导出,也可以使用module.exports导出
    _filename 当前模块的完整路径
    _dirname 当前模块所在文件夹的完整路径

exports和module.exports

  1. 通过exports只能使用.的方式来向外暴露内部变量

  2. module.exports既可以通过.的方式,也可以直接赋值

    1
    2
    
    module.exports.xxx = xxx
    module.exports = {}
    

  1. 包实际上就是一个压缩文件,解压以后还原为目录。符合规范的目录,应该包含
    文件名
    package.json 描述文件
    bin 可执行二进制文件
    lib js代码
    doc 文档
    test 单元测试

2.package.json中的属性含义,json文件中不能写注释

属性名
dependencies 依赖的其他包
description 描述该包的作用
devDependencies 开发环境依赖
name 名字,用于require
version 版本
keywords 关键字,用于搜索
maintainers 贡献者
contributors 维护者
bugs 提交bug地址
licenses 协议
repositories 仓库
homepage 主页
os 系统

npm简介

  1. Node Package Manager
  2. 对于node而言,npm帮助其完成了第三方模块的发布,安装和依赖。借助NPM,node与的三方模块之间形成了很好的一个生态系统。

npm命令

命令
npm-v 查看版本
npm 帮助说明
npm init 创建package.json文件
npm search 包名 搜索模块包
npm install 包名 在当前目录安装包
npm install 包名 -g 全局模式安装包(一般都是一些工具,在计算机里用的,不是在项目中用的)
npm install 包名 –save 安装包并添加自己初始化的package.json的依赖中
npm remove 包名 删除包
npm install 下载当前项目所依赖的包
  1. 在需要安装npm包的目录下用npm init来初始化package.json文件
  2. 通过npm下载的包,通过包名引入即可
  3. node在使用模块名引入模块时,会首先在当前目录的node_modules中寻找是否含有该模块,如果有,则直接使用,如果没有则再去上一级目录寻找,知道找到为止,直到磁盘的根目录,没有则报错

Buffer缓冲区

  1. Buffer的结构和数组很像,操作的方法也和数组类似

  2. 数组中不能存储二进制文件,而buffer就是专门存储二进制文件的

  3. Buffer式node中的核心模块,使用buffer不用引入模块直接使用

  4. 在buffer中存储的都是二进制数据,但是在显示的时候都是以16进制的形式显示

  5. 1
    2
    
    buffer.length  //占用内存的大小,一个汉字占用3个字节,一个字母占用1个字节(8位二进制)
    str.length	//字符串的长度
    
  6. buffer的构造函数已经废弃了

创建和写入

API
Buffer.alloc(size) 创建一个指定大小的buffer,且把内存的数据清空,都为0
Buffer.allocUnsafe(size) 创建一个指定大小的buffer,但是buffer中可能含有敏感数据,不会清空内存,但是这个性能更好
Buffer.from(str) 将一个字符串转化内buffer
buf.toString 将缓冲区中的数据转换为字符串
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//创建10个字节的buffer
let buf2 = Buffer.alloc(10)
//通过索引,来操作buffer中的元素
buf2[0] = 88
buf2[1] = 255
buf2[2] = 0xaa

let str = 'Hello Buffer'
//将一个字符串保存到buffer中
let buf = Buffer.from(str)
console.log(buf.length)

==注意==:

  1. buffer的长度一旦确定,就无法改变,因为buffer是直接操作内存的,alloc(10)就是直接分配10个字节的连续的内存空间
  2. 如果超过8位二进制【0-256),则取后8位

读取

  1. buf[index]
  2. 调用buf.toString(),可以直接把缓冲区中的数据转为字符串
1
2
3
buf[2]  //170,虽然村的时候是16进制,但是只要在控制台输出数字,那一定是10进制

log(buf[2].toString(16))//输出16进制字符串

fs

  1. 通过node来操作系统中的文件

引入

  1. const fs = reqire(‘fs’)

同步文件

  1. 打开文件

    fs.openSync(path,flags[,mode])

    path 要打开文件的路径
    flags 打开文件要做的操作类型 r:只读的 w:可写的
    mode 设置文件的操作权限,一般不传

    返回值:该方法会返回文件的描述符作为结果,我们可以通过该描述符来对文件进行各种操作

  2. 写入内容

    fs.writeSync(fd,string[,position[,ecoding]])

    fd 文件的描述符,需要传递要写入的文件的描述符(变量名)
    string 要写入的内容
    position 写入的起始位置
    ecoding 写入的编码,默认是utf-8

    3.关闭文件

    fs.closeSync(fd)

    1
    2
    3
    4
    5
    6
    
    let fs = require('fs')
    
    let fd = fs.openSync('hello.txt','w')
    
    fs.writeSync(fd,"今天天气真不错",20)
    fs.closeSync(fd)
    

异步文件

  1. 打开

    fs.open(path,flags[,mode],callback)

    除了callback是回调函数外,其他和同步相同,两个参数

    err:错误对象,如果没有错误则为null

    fd:文件的描述符

  2. 写入

    fs.write(fd,callback)

  3. 关闭

    fs.close(fd,callback)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
let fs = require('fs')

fs.open("hello2.txt", 'w', function (err, fd) {
    if (!err) {
        fs.write(fd, "这是异步回调的内容", function (err, written, string) {
            if (!err) {
                console.log('写入成功')
            }
            //关闭文件
            fs.close(fd,function (err) {
                if(!err){
                    console.log('文件已关闭')
                }
            })
        })
    } else {
        console.log(err)
    }
})

简单文件

异步:fs.writeFile(file,data[,options],callback)

==注意==:options是可选项,默认写入w,utf-8,{flag:‘r’}进行修改,mode:文件权限

同步:fs.writeFileSync(file,data[,options])

1
2
3
4
5
6
let fs = require('fs')
fs.writeFile('hello3.txt', '这是通过writeFile写入的内容',{flag:'r'}, function (err) {
    if (!err) {
        console.log('写入成功')
    }
})

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/%E6%89%93%E5%BC%80%E6%96%B9%E5%BC%8F.png

如果要写磁盘的位置用绝对路径

流式文件

  1. 同步,异步,简单文件的写入都不适合大文件的写入,性能较差,容易导致内存溢出

可写流

fs.createWriteStream(path[,options]) //文件路径和配置参数

只要流存在就可以一直写入文件内容

1
2
3
4
5
6
let fs = require('fs')
let ws= fs.createWriteStream('hello3.txt')
//向文件中输出内容
ws.write("通过可写流写入文件内容")
ws.write("通过可写流写入文件内容")
ws.write("通过可写流写入文件内容")

监听

  1. 可以通过监听流的open和close事件来监听流的打开和关闭,用once事件监听

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    let fs = require('fs')
    let ws= fs.createWriteStream('hello3.txt')
    //向文件中输出内容
    ws.write("通过可写流写入文件内容")
    ws.write("通过可写流写入文件内容")
    ws.write("通过可写流写入文件内容")
    
    ws.once('open',function () {
        console.log("流打开了")
    })
    ws.once('close',function () {
        console.log("流关闭了")
    })
    ws.end() //这里不能用close,相当于拔掉了水管的输出端,end是输入端
    

文件读取

同步

异步

简单

fs.readFile(path[,options],callback)

fs.readFileSync(path[,options]) //通过返回值

path 要读取的文件路径
options 读取的选项
callback(err,data) 回调函数,读取返回的内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
let fs = require('fs')
fs.readFile('hello3.txt',function (err,data) {
    //读取
    if(!err){
        console.log(data.toString())
        //写入
        fs.writeFile('hello4.txt',data,function (err) {
            if(!err){
                console.log('文件写入成功')
            }

        })
    }else{
        console.log(err)
    }
})

流式

  1. 如果文件小,只读一次
  2. 如果文件大,会分多个buffer读取,每次65536个字节的数据,避免占用大量内存空间
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let fs = require('fs')
//可读流
let rs = fs.createReadStream('hello4.txt')
rs.once('open',function () {
    console.log('可读流打开')
})
rs.once('close',function () {
    console.log('可读流关闭')
})
//如果要读取可读流中的数据,必须绑定一个data事件,会自动读取数据
rs.on("data",function (data) {
    console.log(data)
})

读取后写入其他文件,注意可写流要在可读流关闭时关闭

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
let fs = require('fs')
//可读流
let rs = fs.createReadStream('hello4.txt')
//可写流
let ws  =fs.createWriteStream('hello5.txt')
rs.once('open',function () {
    console.log('可读流打开')
})
rs.once('close',function () {
    console.log('可读流关闭')
    ws.close()
})
ws.once('open',function () {
    console.log('可写流打开')
})
ws.once('close',function () {
    console.log('可写流关闭')
})
//如果要读取可读流中的数据,必须绑定一个data事件,会自动读取数据
rs.on("data",function (data) {
    console.log(data)
    //将读取的数据写入可写流中
    ws.write(data)
    //数据写入完毕关闭可写流,在可读流关闭时关闭
})

简单的写法

rs.pipe(ws)

1
2
3
4
5
let fs = require('fs')
//可读流
let rs = fs.createReadStream('hello4.txt')
//pipe()可以将可读流中的数据直接输出到可写流中
rs.pipe(ws)

其他方法

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/fs%E5%85%B6%E4%BB%96.png

callback参数err,data

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/fs%E5%85%B6%E4%BB%962.png

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/fs%E5%85%B6%E4%BB%963.png

watchFile中的functionn(curr,prev)

这两个参数都是stats对象,可以用属性

options是对象,可以修改文件的监视时间频率

formidable模块

https://www.cnblogs.com/abab301/p/9489000.html

bcrypt加密

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/bcrypt.png

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/bcrypt%E4%BE%9D%E8%B5%96.png

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/bcrypt%E5%BA%94%E7%94%A8.png

文件上传

前端读取

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/%E5%89%8D%E7%AB%AF%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96.png

后端

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6.png

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B62.png

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B63.png

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/%E4%BF%9D%E5%AD%98%E6%96%87%E4%BB%B6%E8%B7%AF%E5%BE%84%E5%88%B0%E6%95%B0%E6%8D%AE%E5%BA%93.png

==注意==:

  1. 不能直接保存path,用户是通过url访问服务器的资源,url的/实际就是服务器端的public文件夹,所以要split(‘public’)