node简介

Node.js 在浏览器之外运行 V8 JavaScript 引擎(Google Chrome 的内核)。 这使得 Node.js 的性能非常好。
Node.js 应用程序在单个进程中运行,无需为每个请求创建新的线程。 Node.js 在其标准库中提供了一组异步的 I/O 原语,以防止 JavaScript 代码阻塞,通常,Node.js 中的库是使用非阻塞范式编写的,使得阻塞行为成为异常而不是常态。

  • node是一款对ES标准实现的JS引擎
  • js是在浏览器运行,浏览器是在客户端运行
  • 通过node可以使js在服务器中运行,和window等系统进行交互,node就是一款使用js编写的web服务器
  • Node可以在后台来编写服务器
    • Node编写服务器都是单线程的服务器
  • Node仅仅对ES标准进行了实现,所以在Node中不包含DOM 和 BOM
  • Node中可以使用所有的内建对象
    String Number Boolean Math Date RegExp Function Object Array
    而BOM和DOM都不能使用
    但是可以使用 console 也可以使用定时器(setTimeout() setInterval())
  • 传统的服务器都是多线程的
    • 每进来一个请求,就创建一个线程去处理请求
  • Node的服务器单线程的
    • Node处理请求时是单线程,但是在后台拥有一个I/O线程池
  • node底层是使用c++的编写的
  • node的中js引擎使用的chrome的v8引擎
  • node的特点:
    1.非阻塞、异步的I/O
    2.事件和回调函数
    3.单线程(主线程单线程,后台I/O线程池)
    4.跨平台

node命令行窗口

  • 常用指令
    • dir 表示列出当前目录下的所有文件
    • cd 目录名 表示进入到指定的目录
    • md 目录名 表示创建一个文件夹
    • rm 目录名 表示删除一个文件夹
  • 目录
    • . 表示当前目录
    • .. 表示上一级目录
  • 环境变量(window系统中的变量)
    • path 环境变量中保存的是一个一个的路径,路径之间用;隔开
      C:\work\jdk\jdk1.7.0_75/bin;
      %CATALINA_HOME%/bin;
      C:\work\soft\tools\AppServ\Apache24\bin;
      C:\work\soft\tools\AppServ\php5;
      C:\Users\lilichao\AppData\Local\Programs\Fiddler;
      C:\work\environment\Egret\Egret Wing 3\bin;
      C:\Users\lilichao\AppData\Roaming\npm;
      C:\Program Files\MongoDB\Server\3.2\bin;
      C:\Users\lilichao\Desktop\hello
    • 作用
      • 当在命令行窗口打开一个文件或调用一个程序时,系统会首先在当前目录下寻找文件程序, 如果找到了则直接打开;如果没找到则会到环境变量path的路径中寻找;如果没找到则报错(作用域链)
      • 所以可以将一些经常需要访问的程序和文件路径添加到path中,这样就可以在任意位置来访问这些文件和程序了

进程和线程

  • 进程
    • 进程负责为程序的运行提供必备的环境
    • 进程就是一个一个的工作计划(工厂中的车间)
  • 线程
    • 线程是计算机最小的运算单位,负责执行进程中的程序(工厂中的工人)
      线程是干活的
    • 单线程:进程只有一个线程(一个人干),js是单线程的,浏览器(js)是单线程的
    • 多线程:一个程序中可以同时运行多个线程来执行(多个人干一个活),存在并发的问题

I/O (Input/Output)

  • I/O操作指的是对磁盘的读写操作
  • 客户端发送请求与网速有关,服务器响应请求与带宽有关,I/O的操作(另一个线程)阻塞了客户端请求线程,
    客户端请求线程只能等待,导致速度慢;可以减少客户端请求线程
    Image text

node执行js文件

  • 将代码写在js文件中,打开命令行窗口,进入到js文件所在的目录,然后执行:node js文件名

模块化简介

  • 降低代码的耦合性和可以复用代码
  • ES5中没有原生支持模块化,我们只能通过script标签引入js文件来实现模块化
  • 在node中为了对模块管理,引入了CommonJS规范
    • 模块的引用
      • 使用 require()函数来引入一个模块
        • 例子:
          var 变量 = require("模块的标识");
    • 模块的定义
      • 在node中一个js文件就是一个模块
      • 在模块中存在一杯module对象,代表模块自身,exports是module的属性
        • exports和module.exports
          • 通过exports只能使用.的方式来向外暴露内部变量
          • 而module.exports既可以通过.的形式,也可以直接赋值
      • 默认情况下在js文件中编写的内容,都是运行在一个独立的函数中(立即调用函数),而不是全局作用域,所以一个模块中的变量和函数在其他模块无法访问
      • 导出变量和函数
        • 使用 exports (向外部暴露属性或方法)
          • 例子:
            exports.属性 = 属性值;
            exports.方法 = 函数;
        • 使用module.exports
          • 例子:
            // exports指向module.exports
            module.exports.属性 = 属性值;
            module.exports.方法 = 函数;
            module.exports = {
            name: '孙悟空',
            sayName: function() {
            console.log('孙悟空')
            }
            }; // 修改对象,该方式导出数据成功
            exports = {
            name: '孙悟空',
            sayName: function() {
            console.log('孙悟空')
            }
            }; // 修改变量,因此该方式导出数据不成功
        • 模块的标识
          • 模块的标识就是模块的名字或路径
            • node通过模块的标识来寻找模块的
              • 对于核心模块(npm中下载的模块),直接使用模块的名字对其进行引入
                var fs = require("fs");
                var express = require("express");
              • 对于自定义的文件模块,需要通过文件的路径来对模块进行引入,路径可以是绝对路径,如果是相对路径必须以./或 ../开头
                var router = require("./router");

判断js文件中的内容是否是全局变量

  • 在node中有一个全局对象global,作用和网页中window类似,在全局中创建的变量/函数会作为global的属性/函数保存
    var a = 1; // 不是全局变量,
    b = 2; // 全局变量
    console.log(global.a) // undefined
    console.log(global.b) // 2
    console.log(arguments) // 封装函数中的实参,arguments(类数组)只有函数中有
  • js文件包裹的函数
    • 实际上模块中的代码都是包装在一个函数中执行的,并且在函数执行时,同时传递进了5个实参
      // 当node在执行模块中的代码时,它会首先在代码的最顶部,添加如下代码
      function(exports, require, module, __filename, __dirname) {
      // 在代码的最底部,添加如下代码
      }
      • exports
        • 该对象用来将变量或函数暴露到外部
      • require
        • 函数,用来引入外部的模块
      • module
        • module代表的是当前模块本身
        • exports就是module的属性
        • 既可以使用 exports 导出,也可以使用module.exports导出
      • __filename
        • 当前模块的完整路径(C:\Users\lilichao\WebstormProjects\class0705\01.node\04.module.js)
      • __dirname
        • 当前模块所在文件夹的完整路径(C:\Users\lilichao\WebstormProjects\class0705\01.node)

包 package简介

  • 将多个模块组合为一个完整的功能,就是一个包
  • 包结构
    • bin:二进制的可执行文件,一般都是一些工具包中才有
    • lib:js文件
    • doc:文档
    • test:测试代码
    • package.json:包的描述文件
    • package.json
      • 它是一个json格式的文件,位于包的根目录下,里面保存了包各种相关的信息,json文件不能写注释
        name 包名
        version 版本
        dependencies 依赖
        main 包的主要的文件
        bin 可执行文件
        scripts 命令

npm简介(Node Package Manager)

  • npm完成第三方模块的发布、安装和依赖(安装a,发现使用a依赖哪些包,会自动全部下载)等,安装完node自带npm
  • npm命令
    • npm -v
      • 查看npm的版本
    • npm init
      • 初始化安装package.json
    • npm version
      • 查看所有模块的版本
    • npm search 包名
      • 搜索包
    • npm install / i 包名
      • 安装包
    • npm remove / r 包名
      • 删除包
    • npm install 包名 --save
      • 安装包并添加到依赖中
    • npm install
      • 下载当前项目所依赖的包
    • npm install 包名 -g
      • 全局安装包(全局安装的包一般都是一些工具,一般不是在项目中使用的,而是在计算机中使用的,编译css文件,给项目打包的)
    • npm install 包名 –registry=地址
      • 从镜像源安装
    • npm config set registry=地址
      • 设置镜像源
  • 配置cnpm
    • 镜像服务器
    • 直接安装cnpm,安装淘宝提供的cnpm,并更改服务器地址为淘宝的国内地址,命令:npm install -g cnpm –registry=https://registry.npm.taobao.org
    • node搜索包的流程
      • npm下载的包都放到node_modules文件夹中,通过npm下载的包,直接用包名引入
      • node在使用模块名字引入模块时,首先在当前目录的node_modules中寻找是否含有该模块,如果有则直接使用,如果没有则去上一级目录的node_modules中寻找,以此类推,直到找到为止,直到找到磁盘的根目录,如果依然没有,则报错(跟作用域一样)

Buffer(缓冲区)

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

  • 数组中不能存储二进制的文件,而buffer就是专门用来存储二进制数据

  • 使用buffer不需要引入模块,直接使用即可

  • 在buffer中存储的都是二进制数据,但是在在计算机中显示时都是以16进制的形式

    • buffer中每一个元素的范围是从00 - ff 0 - 255
      00000000 - 11111111
      计算机 一个0 或一个1 我们称为1位(bit)

      8bit = 1byte(字节)// 传输数据中最小的单位是1个字节
      1024byte = 1kb
      1024kb = 1mb
      1024mb = 1gb
      1024gb = 1tb

    • buffer中的一个元素,占用内存的一个字节

  • Buffer的大小一旦确定,则不能修改,Buffer实际上是对底层内存的直接操作

  • Buffer的方法

    • Buffer.from(字符串)
      • 将一个字符串中内容保存到一个buffer中
        var str = "Hello 尚硅谷";
        //将一个字符串保存到buffer中
        var buf = Buffer.from(str);

        //console.log(buf.length); //占用内存的大小,在内存中的字节数,1个汉字 = 3bit,1个字母=1bit
        //console.log(str.length);//字符串的长度
        //console.log(buf);
    • buf.toString()
      • 将buffer转换为一个字符串,将缓冲区中的数据转换为字符串
        var buf4 = Buffer.from("我是一段文本数据");
        console.log(buf4.toString()); // 我是一段文本数据
    • Buffer.alloc(size)
      • 创建一个指定大小的buffer对象,创建并且清空
        //创建一个指定大小的buffer
        //buffer构造函数都是不推荐使用的
        //var buf2 = new Buffer(10);//10个字节的buffer
        //console.log(buf2.length);

        //创建一个10个字节的buffer
        var buf2 = Buffer.alloc(10); // <Buffer 00 00 00 00 00 00 00 00 00 00>
        //通过索引,来操作buf中的元素
        buf2[0] = 88; // 十进制,58
        buf2[1] = 255;
        buf2[2] = 0xaa; // 十六进制(0x),aa
        buf2[3] = 255;
        buf2[10] = 15; // 无效,超出长度

        //只要数字在控制台或页面中输出一定是十进制
        console.log(buf2[2]); // 170 十进制
        console.log(buf2[2].toString(16)); // aa 十六进制

        /*for(var i=0 ; i<buf2.length ; i++){
        console.log(buf2[i]);
        }*/
    • Buffer.allocUnsafe(size)
      • 创建一个指定大小的buffer对象,可以包含敏感数据,性能好
        // Buffer.allocUnsafe(size) 创建一个指定大小的buffer,但是buffer中可能含有敏感数据,分配空间但不清空,可能会保存上次的保存信息
        var buf3 = Buffer.allocUnsafe(10);
        console.log(buf3); // <Buffer 18 1e 4a 00 00 00 00 00 90 3c>

文件系统(File System)

简介

  • 文件系统简单来说就是通过Node来操作系统中的文件
  • 使用文件系统,需要先引入fs模块,fs是核心模块,直接引入不需要下载
  • 在Node通过fs模块来对系统中的文件进行操作,fs模块是node中已经继承好了,不需要在使用npm下载,直接引入即可
    // 引入fs
    var fs = require('fs')
  • fs模块中的大部分操作都提供了两种方法,同步方法和异步方法
    • 同步方法带sync:不会阻塞程序执行,在操作完成时,通过回调函数将结果返回,直接return返回
    • 异步方法没有sync,都需要回调函数:阻塞程序执行,除非操作执行完,否则不会向下执行代码

同步文件的写入

  • (隐患:运行出错,整个程序停止,同步处理异常很麻烦)

  • 1、打开文件

    //打开文件
    var fd = fs.openSync("hello.txt" , "w");
    console.log(fd)
    • fs.openSync(path, flags[, mode])

      • path 要打开文件的路径
      • flags 打开文件要做的操作的类型
        • r 只读的
        • w 可写的
      • mode 设置文件的操作权限,一般不传
      • 返回值:该方法会返回一个文件的描述符作为结果,我们可以通过该描述符来对文件进行各种操作
    • 2、向文件中写入内容

      //向文件中写入内容
      fs.writeSync(fd , "今天天气真不错~~~", 2);
      • fs.writeSync(fd, string[, position[, encoding]])
        • fd 文件的描述符,需要传递要写入的文件的描述符
        • string 要写入的内容
        • position 写入的起始位置
        • encoding 写入的编码,默认utf-8
    • 3、保存并关闭文件

      //关闭文件
      fs.closeSync(fd);
      console.log("程序向下执行~~~");
      • fs.closeSync(fd)
        • fd 要关闭的文件的描述符

异步文件的写入

-(运行出错,只是该部分出错;代码更加严谨)

  //打开文件,异步没有返回值,只要有返回值就是同步的
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("文件已关闭~~~");
}
});
});
}else{
console.log(err);
}
});

console.log("程序向下执行~~~");
  • 1、打开文件

    • fs.open(path, flags[, mode], callback)
    • 异步调用的方法,结果都是通过回调函数的参数返回的
    • 回调函数两个参数:
      • err 错误对象,如果没有错误则为null
      • fd 文件的描述符
  • 2、用来异步写入一个文件

    • fs.write(fd, string[, position[, encoding]], callback)
  • 3、保存并关闭文件

    • fs.close(fd, callback)

简单文件写入

//引入fs模块
var fs = require("fs");
fs.writeFile("hello3.txt","这是通过writeFile写入的内容",{flag:"r+"} , function (err) {
if(!err){
console.log("写入成功~~~");
}else{
console.log(err);
}
});

//C:\\Users\\lilichao\\Desktop\\hello.txt 用\转义
//C:/Users/lilichao/Desktop/hello.txt
fs.writeFile("C:/Users/lilichao/Desktop/hello.txt","这是通过writeFile写入的内容",{flag:"w"} , function (err) {
if(!err){
console.log("写入成功~~~");
}else{
console.log(err);
}
});
  • 异步:fs.writeFile(file, data[, options], callback)
  • 同步:fs.writeFileSync(file, data[, options])
    • file 要操作的文件的路径
    • data 要写入的数据
    • options 选项(对象),可以对写入进行一些设置 {flag: ‘w’}
    • callback 当写入完成以后执行的函数
      • flag
        • r 只读
        • w 可写
        • a 追加

流式文件写入

  • (同步、异步、简单文件的写入都不适合大文件的写入,性能较差,容易导致内存溢出)
     var fs = require("fs");
    var ws = fs.createWriteStream("hello3.txt");
    ws.once("open",function () {
    console.log("流打开了~~~");
    });

    ws.once("close",function () {
    console.log("流关闭了~~~");
    });

    //通过ws向文件中输出内容
    ws.write("通过可写流写入文件的内容");
    ws.write("今天天气真不错");
    ws.write("锄禾日当午");
    ws.write("红掌拨清清");
    ws.write("清清真漂亮");

    //关闭流
    ws.end();
  • 创建一个可写流:fs.createWriteStream(path[, options])
    • path,文件路径
    • options 配置的参数
  • 可以通过监听流的open和close事件来监听流的打开和关闭
    • on(事件字符串,回调函数)
      • 可以为对象绑定一个事件
    • once(事件字符串,回调函数)
      • 可以为对象绑定一个一次性的事件,该事件将会在触发一次以后自动失效

同步读取和异步读取

  • 打开文件

    • fs.open(path, flags[, mode], callback)
    • fs.openSync(path, flags[, mode])
  • 读写文件

    • fs.write(fd, string[, position[, encoding]], callback)

    • fs.writeSync(fd, string[, position[, encoding]])

    • fs.read(fd, buffer, offset, length, position, callback)

    • fs.readSync(fd, buffer, offset, length, position)

  • 关闭文件

    • fs.close(fd,callback)
    • fs.closeSync(fd);

简单文件读取

var fs = require("fs");
var path = "C:/Users/lilichao/Desktop/笔记.mp3";

fs.readFile("an.jpg" , function (err , data) {
if(!err){
//console.log(data);
//console.log(data.toString());
//将data写入到文件中
fs.writeFile("C:/Users/lilichao/Desktop/hello.jpg",data,function(err){
if(!err){
console.log("文件写入成功");
}
});
}
});
  • fs.readFile(path[, options], callback)
  • fs.readFileSync(path[, options])
    • path 要读取的文件的路径
    • options 读取的选项
    • callback回调函数,通过回调函数将读取到内容返回(err , data)
      • err 错误对象
      • data 读取到的数据,会返回一个Buffer,读出的数据有可能是图片、音频或其他文件

流式文件读取

  • 适用于一些比较大的文件,可以分多次将文件读取到内存中
    var fs = require("fs");

    //创建一个可读流
    var rs = fs.createReadStream("C:/Users/lilichao/Desktop/笔记.mp3");
    //创建一个可写流
    var ws = fs.createWriteStream("a.mp3");

    //监听流的开启和关闭
    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) {
    //console.log(data);
    //将读取到的数据写入到可写流中
    ws.write(data);
    });

    //pipe()可以将可读流中的内容,直接输出到可写流中
    rs.pipe(ws);