Nodejs(一)

108 阅读11分钟

一、什么是 node?

一个基于 Chrome V8 解析引擎的 JavaScript 运行时环境

1、由来 :

-   把浏览器内的 JS 解析引擎拿出来, 和其他的内容进行组装
-   变成一个 新的内容, 叫做 NodeJS

2、前端 JS 和 NodeJS 的区别

1、

  • 前端 JS
    • 当 JS 被引入到 HTML 文件中, 放在浏览器中执行的时候 (JS 的组成: BOM + DOM + ECMAScript)
      • 他在这个时候, 才会有所谓的 BOM 和 DOM
      • BOM: 浏览器对象模型 浏览器提供给我们的
      • DOM: 文档对象模型 HTML 提供给我们的
  • NodeJS
    • 把 JS 从 HTML 文件中拿出来, 放在 电脑系统中直接运行
    • 此时没有所谓的 DOM 和 BOM
    • 但是因为是在 电脑系统中运行
      • 可以操作 文件/文件夹 (I/O; input/output)
      • 可以操作电脑系统
      • 可以操作数据库
      • ...

2、

  • 前端 JS
    • 运行时可以操作模块发开发(ES6 模块化), 也可以采用非模块开发
    • 为什么可以采用非模块化
    • 因为我们把所有的 JS 文件, 引入到某一个 HTML 文件中, 去使用
  • NodeJS
    • 运行时 必须采用 模块化开发
    • 因为他是直接执行 JS 文件, 没有一个统一的 html 文件去引入所有的 JS 文件
    • 使用的 模块化语法 是 CommonJS

3、JS 中 代码是没有错误的

  • 关键是我们要把 JS 运行在那个环境(要把代码运行在哪里)
  • 假设 将来需要把这个 JS 文件放在前端使用(引入到 HTML, 并运行在浏览器中)
    • 那么可以在 JS 中书写 BOM 和 DOM 相关的东西
  • 假设 将来需要把这个 JS 文件放在 NODEJS 中使用
    • 那么就不能在 JS 中书写 DOM 和 BOM 相关的 东西
    • 但是 此时可以书写 操作 文件/文件夹相关的代码

4、NodeJS 的作用

-   按照 CommonJS 模块化开发语法的规范进行书写代码
-   能够 使用 JS 这个语言 进行后端代码的开发

二、命令行基本操作

注意: 此处仅为了能够满足使用 nodejs

  • 什么是 命令行

    • 个人喜欢叫: "小黑窗/黑窗口"
    • win: cmd / powerShell
  • 打开 小黑窗

    • win
      • 方式 1
        1. 然下 win + r 键
        2. 输入 cmd 后按下回车 注意: 打开的是电脑系统个人目录
      • 方式 2
        1. 进入某个文件夹
        2. 在地址栏位置输入 cmd 按下回车 注意: 打开的是 当前文件夹下的
  • 认识小黑窗

    • 最开始的位置有一个东西 表明的是文件结构, 就是当前这个小黑窗是在那个文件夹内的
  • 黑窗口的指令

    1. 查看当前目录下的内容
      • 输入指令: dir
    2. 切换目录
      • 输入指令: cd 文件夹名称
    3. 退回上一级目录
      • 输入指令: cd ..
    4. 清屏
      • win: cls
      • mac: clear

三、如何利用 node 执行 js 代码

  • 因为 node 是直接在电脑操作系统上进行 JS 代码的执行
  • 其实就是 在 小黑窗 内直接执行 JS 文件
  • 小黑窗内执行 JS 代码
    • 方式 1:
      • 打开 小黑窗, 目录无所谓
      • 输入命令: node 按下回车
      • 会进入 JS 代码编辑模式
        • 此时是不能执行 cmd 命令的, 只能书写 JS 代码
      • 按下 ctrl + c 退出当前环境
      • 缺点: 书写的代码无法保存
    • 方式 2:
      • 把你要执行的 JS 代码 书写在一个 .js 文件内
      • 打开命令行, 切换目录到 JS 文件所在的目录
      • 输入指令: node 文件名

四、node 模块化开发

  • node 必须模块化开发
  • node 自带的所有内容都是以模块的形式出现的
  • 模块化语法
  • 导出
    1. 每一个 JS 文件天生自带一个变量叫做 module
    2. 表示的是当前自己这个模块的所有信息
    3. 每一个文件默认导出一个对象
    4. 语法:
      • 如果你想向默认导出的对象内添加成员
        • module.exports.属性名 = 属性值
        • exports.属性名 = 属性值
        • node 的 每一个 JS 文件, 内部天生自带一个 变量 叫做 exports
        • 变量内部存放的是 指向 module.exports 这个对象的 地址
      • 如果你想修改这个默认导出的内容
        • module.exports = 值

1、给 module.exports 直接赋值 (任意类型无所谓)

module.exports = 'QF001'
module.exports = 10086
module.exports = true
module.exports = false
module.exports = [1, 2, 3]
module.exports = function () {
    console.log("你好");
};
module.exports = () => {
    console.log("你好");
};
const obj = {
    id: 'QF001',
    name: '张三',
    age: 18
}
module.exports = obj
console.log(module)

2、给 module.exports 这个对象内添加一些属性 (属性的值无所谓)

module.exports.id = 'QF001'
module.exports.name = '张三'
module.exports.age = 18

// 因为 module.exports 和 exports 是同一个地址, 所以此时的代码会修改原本的 name 值
exports.name = '李四'


exports.info = {
    w: 10086,
    h: 10010
}

3、给 exports 这个对象内添加一些属性 (属性的值无所谓)

    module.exports.id = 'QF001'
module.exports.name = '张三'
module.exports.age = 18

// 因为 module.exports 和 exports 是同一个地址, 所以此时的代码会修改原本的 name 值
exports.name = '李四'


exports.info = {
    w: 10086,
    h: 10010
}


// /**
//  *  此时我们会切断 exports 和 module.exports 之间的关联
//  *  所以这行代码没有导出的功能
// */
exports = [1, 2, 3, 4, 5]

// /**
//  *  因为上边的一行代码将 exports 和 module.exports 之间的关联 切断了
//  *  所以现在的这个 name 属性 不会生效
// */
exports.name = '王五'

console.log('导出的内容, 在你导入的时候我会执行一遍', module.exports)
  • 导入
    1. 每一个 JS 文件天生自带一个方法叫做 require()
    2. 语法: require('地址') 注意: 如果地址书写的时候, 文件后缀是 .js, 那么可以省略后缀不写
    3. 返回值: 该文件的 module.exports (该文件向外暴露的内容)
    /**
 *  在 node 中 导入的文件如果后缀是 .js 那么可以省略后缀
 * 
 *  导入文件的时候会先将这个文件整体执行一遍
 *  然后将 导出的内容, 拿到当前文件内
*/

const res = require('./04_node的模块化')
console.log('导入的数据: ', res)
  • 模块分类
    1. 自定义模块: 自己写的 JS 文件
    2. 内置模块: node 给我们提供的模块, 直接引入使用即可
    3. 第三方模块
      • 由其他人写好上传到某一个仓库内(npm)
      • 我们去这个仓库内(npm)下载到本地, 然后引入使用

五、node 内置模块 fs

node 给出的内置模块, 专门用来操作 文件/文件夹

    const fs = require('fs')
    console.log(fs)
  1. 异步读取文件

    • 语法: fs.readFile(文件路径, 配置参数, 回调函数)
    • 参数:
      • 文件路径: 必填
      • 配置参数: 不写默认是 buffer 可以手动配置为 utf-8
      • 回调函数: 必填, 接受两个参数, 第一个为报错信息, 第二个为正确读取到的文件的内容(字符串格式的)
    fs.readFile("./index1.txt", "utf-8", (error, data) => {
        if (error) return console.log(error);
        console.log(data);
    });
    
  2. 同步读取文件

    let str = fs.readFileSync("./index1.txt", "utf-8");
    console.log(str);
    
  3. 异步写入文件

    • 语法: fs.writeFile(文件地址, 写入内容, 回调函数)
    • 参数:
      • 文件地址:
        • 这个文件, 直接讲内容写入到指定文件内
        • 没有这个文件, 创建一个出来, 然后写入到指定文件内
      • 写入内容:
        • 符串格式的内容, 将这段文本直接写入到指定文件中, 并覆盖这个文件之前的所有内容
      • 回调函数:
        • 必写, 哪怕这个函数什么也不做, 也必须要写
    fs.writeFile("./index.txt", "你好 世界", () => {
        console.log("写入完成");
    });
    
  4. 同步写入文件

    fs.writeFileSync("./index.txt", "hello word");
    console.log("node end");
    
  5. 向文件内 追加数据

   fs.appendFile('./index.txt', '我是一个新加入的文本', () => {})

六、内置模块 path

node 自带的模块, 专门用于和路径相关的操作

    const path = require("path");
    console.log(path);
  1. 绝对路径
    • C:/a/b/c/d.html
  2. 相对路径
    • ./d.html
    • ../c/d.html
  • 组装一个相对路径 path.join(路径片段 1, 路径片段 2, 路径片段 3)
    const res = path.join("a", "b/c", "d", "e.html");
    console.log(res); // a\b\c\d\e.html
    
  • 组装一个绝对路径 path.resolve(路径片段 1, 路径片段 2, 路径片段 3)
    const res1 = path.resolve("a", "b/c", "d", "e.html");
    const res2 = path.resolve("C:", "b/c", "d", "e.html");
    console.log(res1); // C:\Users\41099\Desktop\qianfeng-prepares-lessons\06_周\05_天\code\06_内置模块path\a\b\c\d\e.html
    console.log(res2); // D:\b\c\d\e.html
    
  • 组装一个解析路径 path.parse(路径)
    const res = path.parse(
        "C:/Users/41099/Desktop/qianfeng-prepares-lessons/06_周/05_天/code/06_内置模块path/a/b/c/d/e.html"
    );
    console.log(res);
    /*
        {
            // 根路径
            root: 'C:/',
            // 完整文件目录(截止到目录, 不会到文件)
            dir: 'C:/Users/41099/Desktop/qianfeng-prepares-lessons/06_周/05_天/code/06_内置模块path/a/b/c/d',
            //  完整文件名
            base: 'e.html',
            // 文件后缀名
            ext: '.html',
            // 文件名
            name: 'e'
        }
    */
    

七、内置模块 url

node 自带的模块, 专门用来操作 url 地址的

    const url = require('url')
  • url.parse('地址', 是否深度解析);
    • 地址: 必填
    • 是否深度解析
      • 默认是 false, 不深度解析, 可以手动配置为 true
      • 深度解析其实就是把 对象中的 query 解析为 对象格式

1、false

    const res = url.parse('http://localhost:8888/cart.html?goodsId=10086&userId=10010')
    console.log(res)
/*
    Url {
        protocol: 'http:',
        slashes: true,
        auth: null,
        host: 'localhost:8888',
        port: '8888',
        hostname: 'localhost',
        hash: null,
        search: '?goodsId=10086&userId=10010',
        query: 'goodsId=10086&userId=10010',
        pathname: '/cart.html',
        path: '/cart.html?goodsId=10086&userId=10010',
        href: 'http://localhost:8888/cart.html?goodsId=10086&userId=10010'
    }
*/

2、true

const res = url.parse(
    "http://www.baidu.com:8080/a/b/c/index.html?key=value&name=QF001&age=18#abc",
    true
);
console.log(res);
/*
    Url {
        // 协议
        protocol: 'http:',
        slashes: true,
        auth: null,
        // 域(域名+端口号)
        host: 'www.baidu.com:8080',
        // 端口号
        port: '8080',
        // 域名
        hostname: 'www.baidu.com',
        // hash值
        hash: '#abc',
        // 携带的参数
        search: '?key=value&name=QF001&age=18',
        // 查询字符串
        query: 'key=value&name=QF001&age=18',
        // 路径名称
        pathname: '/a/b/c/index.html',
        // 路径(路径名称 + 参数)
        path: '/a/b/c/index.html?key=value&name=QF001&age=18',
        // 完整地址
        href: 'http://www.baidu.com:8080/a/b/c/index.html?key=value&name=QF001&age=18#abc'
    }

    深度解析后的
    Url {
        ...
        query: [Object: null prototype] { key: 'value', name: 'QF001', age: '18' },
        ...
    }

八、内置模块 http

node 自带的一个模块, 用于开启一个 http 服务

  • 服务器
    • 提供 服务 的 机器
      • 服务: 提供一些内容(文件/数据)
      • 机器: 电脑
    • 有一台电脑, 运行了 一个 '软件'
      • 这个 "软件" 可以向外开放一个 "文件夹"(根目录)
      • 当其他电脑访问到这台电脑的时候, 并且制定了访问这个 "软件" 的时候
      • 那么相当于在访问这个文件夹
      • 例子:
        • 一台电脑: 10.11.12.13
        • 软件: 8080
        • 开放的文件夹是: D:/a/b
        • 当你打开浏览器访问 http:10.11.12.13:8080 的时候, 就是在访问这台电脑上的 D:/a/b
    • node 就可以利用 http 模块来充当 "软件" 启动服务

初始搭建步骤

0、引入内置模块

    const http = require("http");

1、创建服务

  • 语法: http.createServer(函数)
    • 函数: 每当前端有一个请求访问这个服务器的时候, 就会执行一次
  • 返回值: 一个服务
const server = http.createServer(() => {
    console.log("前端发一次请求, 我就执行一次");
});

2、给当前服务配置一个端口号

  • 语法: server.listen(端口号(0~65535), 回调函数)
server.listen(8080, () => {
    console.log("启动服务成功~~~");
});

3、创建函数时 函数接收的两个参数

  • 第一个 形参: request, 对应的值为前端请求时携带的请求报文
  • 第二个 形参: response, 表示本次响应的相关信息, 你只要添加到 res 内, 会由服务器自动组装响应报文返回给前端
  • res.end 是一个函数, 这个函数调用的时候 能够关闭当前请求。这个函数可以传递一个参数, 这个参数会传递给请求者

const server = http.createServer((req, res) => {
    fs.readFile('./client/views/index.html', 'utf-8', (err, data) => {
        if (err) return console.log(err)        
        res.end(data)
    })
})

// 2. 给服务器配置一个端口号
server.listen(8080, () => console.log('服务器启动成功~'))

补充---请求

  • 什么算请求?
    1. 在浏览器地址栏输入一个 地址, 然后按下回车
      • 以浏览器为主体在发送请求
      • 服务器返回的内容直接给到浏览器, 显示在页面上
    2. 在浏览器内 以 link script iframe img 等标签请求的内容
      • 例如: <link href="./css/a.css"></link>
      • 例如: <script src="./js/a.js"></script>
    3. 当前页面中的 js 代码内的 ajax 请求
  • 请求的完整地址是什么