Node.js 基础

221 阅读9分钟

要点

  • const exports = [ module.exports = {} ] 原理
// add 移动到一个单独的文件

// 导入
// ./  / 
// 补齐
// .js || .json || .node
const add = require('./add');
console.log(add(1, 1));
console.log(add)

// 如果不是文件的话
// 尝试看看是不是文件夹
// 1. package.json  里面的 main 字段 
// 2. 找里面的 index.js ||.json || .node
const sub = require('./sub');
console.log(sub)

// 如果不是 ./ / 开头的话
// 加载内置模块 第三方模块
const http = require('http');
console.log(http)

// 文件夹以及文件同名
// 先尝试文件
const add = require('./add');
console.log(add)

// 第三方模块 node_modules中
const atest = require('atest');
console.log(atest)
const lodash = require('lodash');
console.log(lodash)

简介

Node.js 就是js,基于Chrome v8 引擎运行在服务端 可以直接操作操作系统

安装(windows 要配置环境变量,重启cmd / vscode)

  • 官网
  • brew

特点

  • 单线程
  • 非阻塞 I/O
    • 访问文件
    • 网络请求
    • 数据库查询
    • 键盘/鼠标交互
  • 事件驱动

用途

  • 工具
    • 构建工具 webpack
    • 编译工具 babel
    • 脚手架 vue-cli
  • 后端服务

客户端和服务端

  • 一个js放在浏览器执行,就是普通的js,放在服务端node环境执行,就是node.js
  • node.js可以搭建服务器
  • 哪个电脑搭建服务器就是服务端,哪个电脑去访问就是客户端(相对)
const http = require('http')
const server = http.createServer((req, res) => {
    res.write('111')
    res.end()
})
server.listen(3000)
每次修改需要重新启动
node http.js

nodemon 热更新,不用手动重启
npm install nodemon -g
nodemon http.js

node中的模块化

  • node 遵循common.js规范
  • commandjs 早于 esm
  • 针对客户端:AMD sea.js CMD require.js
  • node: 装好后天生的common.js规范,每个文件都是一个独立的模块,变量不会相互污染
  • 模块加载的优先级, 先文件再目录

以文件的形式(以文件模式引入: ./ 不能省略)

Ma.js

console.log("我是Ma.js文件");
require("./Mb");
let a = 10;
class Person{
    constructor(){
        this.name = "张三";
    }
    hobby(){
        console.log("喜欢篮球");
    }
}
// 第一种导出方式
// module.exports = {
//     a,
//     Person
// }

//第二种导出方式
exports.a = a;
exports.Person = Person;

// exports = add;
// 相当于::
// module.exports = {
//     add: add
// }

// exports 是 module.exports 的引用;
// const exports = [ module.exports = {} ]
// export = { }  无法改变module.exports的值,通过 . 可以
// exports = add; 使得上述联系断开
Mb.js
console.log("我是模块b");
index.js

// 以文件模式引入: ./ 不能省略, .js后缀可省略
let Ma = require("./Ma");
console.log(Ma.a)

let cai = new Ma.Person();
cai.hobby();

以目录的形式(以文件模式引入: ./ 不能省略)

a.js

console.log("我是a.js")
require("test");
b.js

console.log("我是b.js")
index.js

console.log("我是index.js");
require("./a");
require("./b");
在home目录外的index.js中引入,并运行这个index.js
自动会去查找home 目录中的index.js

require("./home");

node_modules里的模块(引入时不需要加./ ,加了会报错)

package.json 

描述、功能性的文件,既有描述,也有功能
下次找mytest 模块,先读package.json, 读到main 去找主入口

{
    "name": "mytest",
    "version": "1.0",
    "main": "main.js" //主入口,不写默认index.js
}
a.js

console.log('a.js')
b.js

console.log('b.js')
index.js

require('./a')
require('./b')

module.exports = {
    a: 10,
    b() {
        console.log('o my gad')
    }
}
main.js

console.log('main.js')
// ***********************************************
// 其他地方引入时:

// node_modules里的模块;
// 不需要加 ./, 自动找index.js

// 主入口为 index.js
// let {a,b} = require("mytest");
// console.log(a, b);
// b();

// 主入口改成main.js
require("mytest")
  • 主入口为 index.js

  • 主入口改成main.js

npm 包管理器

  • node_modules 中放第三方模块
  • npm 包管理器 www.npmjs.com
  • npm install jauery 可以安装前/后端的依赖和模块
  • npm uninstall 删除
  • 内置模块不需要安装,外置模块需要安装

node 中的内置模块:

Buffer,C/C++Addons,Child Processes,
Cluster,Console,Crypto,Debugger,
DNS,Domain,Errors,Events,
File System,
Globals,HTTP,HTTPS,Modules,Net,OS,
Path,Process,P unycode,Query Strings,
Readline,REPL,Stream,
String De coder,Timers,TLS/SSL,
TTY,UDP/Datagram,URL, Utilities,V8,VM,ZLIB;
  • npm init 创建package.json
{
  "name": "code",
  "version": "1.0.0",
  "main": "index.js",
  "dependencies": {
    "jquery": "^3.4.1"
  },
  "devDependencies": {
    "axios": "^0.19.0"
  },
  // 命令
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "description": ""
}

依赖

dependencies:运行依赖,上线后也需要用 jquery、vue、react;
devDependencies:开发依赖,开发时作为开发工具用一下 sass less;
写在这里 npm install 时会自动查找,装到node_modules
node_modules 在本层找,没有则向上找,直到系统根目录 npm root -g

^ 最低兼容版本
  • npm install axios --save

  • npm i axios --save-dev

npm install

工具类的,很多项目都需要用,装到全局。仅与本项目有关系的,装到本项目下:
npm i gulp 装在当前目录下的node_modeules
npm i gulp -g 装在系统根目录 npm root -g  得到全局的node_modeules下

其他

npm updata 更新
npm i jauery@3.4.1 安装指定版本

fs模块

文件操作

异步写法
文件写入
const fs = require("fs"); //文件操作
// 增删改查;
// 1.文件操作  2.目录操作;
// 文件操作
fs.writeFile("1.txt","我是写入的文字11111",function(err){
    if(err){
        return console.log(err);
    }
    console.log("写入成功");
})

const fs = require("fs"); //文件操作

// a:追加写入;w 写入(默认);r:读取(写入这里不行)

fs.writeFile("1.txt","我是追加的文字",{flag:"a"},function(err){
    if(err){
        return console.log(err);
    }
    console.log("写入成功");
})

文件读取
const fs = require("fs"); //文件操作

// 文件读取
fs.readFile("1.txt","utf8",(err,data)=>{
    if(err){
        return console.log(err);
    }
    console.log(data);
})

const fs = require("fs"); //文件
fs.readFile("1.txt",(err,data)=>{
    if(err){
        return console.log(err);
    }
    console.log(data)
    console.log(data.toString());
})

同步
// 所有文件操作 没有加Sync都是异步 否则是同步;

let data = fs.readFileSync("1.txt");
console.log(data.toString());

修改
// 修改;(修改名称);
fs.rename("1.txt","2.txt",err=>{
    if(err){
        return console.log(err);
    }
    console.log("修改成功");
});

删除
// 删除;
fs.unlink("2.txt",(err)=>{
    if(err){
        return console.log(err);
    }
    console.log("删除成功");
})
复制
// 复制; 先读取 在写入 的过程;
// 提供的复制方法
fs.copyFile("index.html","index2.html",err=>{
    if(err){
        return console.log(err);
    }
    console.log("复制成功!");
})
// 自己写的复制
function mycopy(src,dest){
   fs.writeFileSync(dest,fs.readFileSync(src));
}
mycopy("index.html","test2.html");

目录操作

// 创建目录
fs.mkdir("11",err=>{
    if(err){
        return console.log(err);
    }
    console.log("创建成功");
})
// 修改目录名称
fs.rename("11", "22", err => {
    if (err) {
        return console.log(err);
    }
    console.log("修改成功");
})
// 读取目录;(第一个参数是路径)
fs.readdir("22",(err,data)=>{
    if(err){
        return console.log(err);
    }
    console.log(data);
})

// 删除目录(必须是空文件夹/目录)
// 第一个参数是路径
fs.rmdir("22/44",err=>{
    if(err){
        return console.log(err);
    }
    console.log("删除成功");
})

// 判断文件或者目录是否存在

fs.exists("index.html",exists=>{
    console.log(exists);  // true/false
})
// 获取文件或者目录的详细信息;

fs.stat("index.html",(err,stat)=>{
    if(err){
        return console.log(err);
    }
    console.log(stat);
    
    
    // 判断文件是否是文件
    //  let res = stat.isFile();
    
    // 是否是一个文件夹;
    let res = stat.isDirectory();
    console.log(res);
})

// 删除非空文件夹;

// 不进回收站,删除前不备份就没了
// 先把目录里的文件删除-->删除空目录;
// 22
function removeDir(path){
   let data = fs.readdirSync(path);
    // ["33","1.txt","2.html"];
   for(let i=0;i<data.length;i++){
        // 是文件或者是目录; --->?文件 直接删除?目录继续查找;  
        let url = path + "/" + data[i];
        let stat =  fs.statSync(url);
        if(stat.isDirectory()){
            //目录 继续查找;
            removeDir(url);
        }else{
            // 文件 删除
            fs.unlinkSync(url);
        }
   }
    //  删除空目录
   fs.rmdirSync(path);
}
removeDir("22");

buffer 类

buffer 创建

// buffer 创建
// buffer 类  数据格式  不是node中的模块
// new Buffer()
// 16进制呈现,在计算机中是二进制

let buffer = Buffer.alloc(10);
console.log(buffer);

let buffer = Buffer.from("大家好");
console.log(buffer);

let buffer = Buffer.from([0xe5,0xa4,0xa7,0xe5,0xae,0xb6,0xe5,0xa5,0xbd]);
console.log(buffer);
console.log(buffer.toString());

乱码问题

// 乱码问题

let buffer1 = Buffer.from([0xe5,0xa4,0xa7,0xe5]);
let buffer2 = Buffer.from([0xae,0xb6,0xe5,0xa5,0xbd]);
console.log(buffer1.toString());
console.log(buffer2.toString());

let newbuffer = Buffer.concat([buffer1,buffer2]);
console.log(newbuffer.toString());

let buffer1 = Buffer.from([0xe5,0xa4,0xa7,0xe5]);
let buffer2 = Buffer.from([0xae,0xb6,0xe5,0xa5,0xbd]);

let { StringDecoder } = require("string_decoder");
let decoder =  new StringDecoder();
let res1 = decoder.write(buffer1);
let res2 = decoder.write(buffer2);
console.log(res1);
console.log(res2);
console.log(res1+res2);

steam 流

  • 数据/文件切割成小块,依次传递,时间变长,性能变高
const fs = require("fs");
let res = fs.readFileSync("1.txt");
console.log(res)
console.log(res.toString());

const fs = require("fs");

let rs = fs.createReadStream("1.txt");
let ws = fs.createWriteStream("2.txt");

rs.on("data",chunk=>{
    console.log(chunk); // chunk 小方块
})

// 流会把数据分成64kb的小文件传输;

// 创建一个65kb的文件;
let buffer = Buffer.alloc(64*1024);
fs.writeFile("64kb",buffer,err=>{
    if(err){
        return console.log(err);
    }
    console.log("写入成功");
})
const fs = require("fs");
let rs = fs.createReadStream("65kb");
let num = 0;
rs.on("data",chunk=>{
    num++;
    console.log(chunk); // chunk 小方块
    console.log(num);
})

const fs = require("fs");
let rs = fs.createReadStream("64kb");
let num = 0;
rs.on("data",chunk=>{
    num++;
    console.log(chunk); // chunk 小方块
    console.log(num);
})

const fs = require("fs");

let rs = fs.createReadStream("1.txt");
let num = 0;
let str = "";
rs.on("data",chunk=>{
    num++;
    str += chunk;
    // console.log(chunk); // chunk 小方块
    console.log(num);
})
// 流完成了;
rs.on("end",()=>{
    console.log(str);
})

const fs = require("fs");

let rs = fs.createReadStream("1.txt");
let ws = fs.createWriteStream("2.txt");
rs.pipe(ws);

模版引擎

模板引擎:模板引擎是web应用中动态生成html的工具,负责将数据和模板结合;

常见模板引擎有:ejs、jade(现更名为pug)、Handlebars、Nunjucks、Swig等;

使用模板引擎可以是项目结构更加清晰,结构更加合理,让项目维护变得更简单;

  • 什么是模板引擎

  • pug/nunjucks模板引擎

  • 表达式

  • 判断语句

  • 循环语句

  • 宏模式

  • 导入导出

pug模板引擎使用

  • 安装pug

    npm i pug -g

  • pug常用语法

    • pug语法:通过缩进关系,代替以往html的层级包含关系,如 个简单的静态 可以表达为,注意要统一使用tab或者空格缩进,不要混用
    • 内联书写层级,a: img
    • style属性:div(style={width:”200px”,color:”red”})
    • 使用”-”来定义变量,使用“=”把变量输出到元素内;
    • 通过 #{variable} 插 相应的变量值
    • html 元素属性通过在标签右边通过括号包含(可以通过判断来添加)
    • 文本通过在 字前 添加竖线符号“|”可让 jade 原样输出内容 在html标签标记后 通过空格隔开 本内容 在html标签标记后通过添加引号“.”添加块级文本
    • 注释:可以通过双斜杠进 注释,jade有3种注释 式,可以分别对应输出html 注释、 输出html注释、块级html注释
    • 循环:each val in [1,2,3]
    • 判断语句:”if else” case when default
    • mixin:混合模式
    • include common/footer.pug 通过include引入外部文件
  • 练习工具 hade;

    npm i hade -g

nunjucks模板引擎在koa中的应用

  • 安装koa-nunjucks-2

  • 使用nunjucks

    const nunjucks = require('koa-nunjucks-2');
    app.use(nunjucks({
      ext:"html",   //指定模板后缀
      path:path.join(__dirname,'views'), //指定视图目录
      nunjucksConfig:{
        trimBlocks:true   //开启转义,防止xss漏洞
      }
    }))
    
  • 推荐使用”.njk“后缀名

  • nunjucks的语法使用

    • 变量:{{username}}

    • 注释:

      {# Loop through all the users #}
      
    • if

      {% if hungry %}
        I am hungry
      {% elif tired %}
        I am tired
      {% else %}
        I am good!
      {% endif %}
      
    • for

      <h1>Posts</h1>
      <ul>
      {% for item in items %}
        <li>{{ item.title }}</li>
      {% else %}
        <li>This would display if the 'item' collection were empty</li>
      {% endfor %}
      </ul>
      
    • 过滤器

      {{ foo | replace("foo", "bar") | capitalize }}
      
    • 模板继承block/extends

      • 定义父类模板

        <h1>我是公共模板</h1>
            <div class="leftContent">
                {% block left %}
                    这边是左侧的内容
                {% endblock %}
                {% block right %}
                    这边是右侧的内容
                {% endblock %}
                {% block somevalue %}
                    我是一些数据
                {% endblock %}
            </div>
        
      • 继承父类模板

        {% extends "common.html" %}
        {% block left %}
            我是左侧的内容1111
        {% endblock %}
        {% block right %}
            我是右侧的内容11111
        {% endblock %}
        
        {% block somevalue %}
            {{ super() }}
        {% endblock %}
        
    • Macro(宏标签)可以定义可复用的内容,类似与编程语言中的函数

      • 定义
      {% macro pet(animalName,name="小白") %}
          <div>
              这里是一只{{animalName}};他的名字是{{name}}
          </div>
       {% endmacro %}
      
      
      • 调用

        {{pet("狗狗")}}
        
    • include/import

      • include 引入文件

        {% include "footer.html" %}
        
      • import 导入文件

        • 定义
            {% macro pet(animalName) %}
            <p>这是一只{{animalName}}</p>
            {% endmacro %}
            {% macro book(bookName) %}
            <p>这是一本书,名字叫{{bookName}}</p>
            {% endmacro %}
        
        • 调用

          {% import 'somemodule.html' as fn %}
          {{fn.pet("狗狗")}}
          {{fn.book("nodejs从入门到实践")}}