教程.NodeJS的常见用法

代码实例

操作数据库

综合示例如下,设备管理系统(DMS),可以实现通过NodeJS连接MySQL数据库,实现接口,并且可跨域,然后读取到前端页面上。


数据库

使用MySQL数据库,信息如下:

host: 'localhost',
user: 'root',
password: '123456',
database: 'test'

创建 device 表,包含三个字段:id,name,note


前端

html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
    <script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.12/index.js"></script>
    <script src="https://cdn.bootcss.com/qs/6.5.1/qs.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.js"></script>

    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>

<body>
    <div id="app">
        <template>
            <el-card class="box-card membersTab">
                <!-- 查询 -->
                <div style="margin-bottom: 40px;">
                    <el-button @click="getData(input)" style="display: inline-block;" type="primary">查询</el-button>
                    <el-input style="width: 60%;" v-model="input" placeholder="请输入内容"></el-input>
                </div>
                <!-- 新增 -->
                <div style="margin-bottom: 40px;">
                    <el-button type="success" @click="handleInsert(id,name,note)">新增</el-button>
                    <el-input style="width: 20%;" v-model="id" placeholder="请输入id"></el-input>
                    <el-input style="width: 20%;" v-model="name" placeholder="请输入name"></el-input>
                    <el-input style="width: 20%;" v-model="note" placeholder="请输入note"></el-input>
                </div>

                <el-divider></el-divider>

                <!-- 数据表格 -->
                <el-table
                    :data="tableData.slice((pageSettings.currentPage-1)*pageSettings.PageSize,pageSettings.currentPage*pageSettings.PageSize)"
                    stripe style="width: 100%" @sort-change="sortChange">
                    <el-table-column label="id" width="180" sortable prop="id"></el-table-column>
                    <el-table-column label="name" width="180" sortable prop="name"></el-table-column>
                    <el-table-column label="note" width="180" sortable prop="note"></el-table-column>
                    <el-table-column label="操作">
                        <template slot-scope="scope">
                            <el-button size="mini" type="danger" @click="handleDelete(scope)">删除</el-button>
                            <el-button size="mini" type="warning" @click="btn_edit(scope)">编辑</el-button>
                        </template>
                    </el-table-column>
                </el-table>
                <div class="tabListPage">
                    <el-pagination small @size-change="handleSizeChange" @current-change="handleCurrentChange"
                        :current-page="pageSettings.currentPage" :page-sizes="pageSettings.pageSizes"
                        :page-size="pageSettings.PageSize" layout="total, sizes, prev, pager, next, jumper"
                        :total="pageSettings.totalCount">
                    </el-pagination>
                </div>

                <!-- 编辑表单 -->
                <el-dialog title="修改信息" :visible.sync="dialogFormVisible">
                    <el-form :model="form">
                        <el-form-item label="ID" :label-width="formLabelWidth">
                            <el-input v-model="form.id" autocomplete="off"></el-input>
                        </el-form-item>
                        <el-form-item label="NAME" :label-width="formLabelWidth">
                            <el-input v-model="form.name" autocomplete="off"></el-input>
                        </el-form-item>
                        <el-form-item label="NOTE" :label-width="formLabelWidth">
                            <el-input v-model="form.note" autocomplete="off"></el-input>
                        </el-form-item>
                    </el-form>
                    <div slot="footer" class="dialog-footer">
                        <el-button @click="dialogFormVisible = false">取 消</el-button>
                        <el-button type="primary" @click="handleUpdate(form)">确 定</el-button>
                    </div>
                </el-dialog>
            </el-card>
        </template>
    </div>
    <script>
        const app = new Vue({
            el: '#app',
            data() {
                return {
                    input: '',
                    id: '',
                    name: '',
                    note: '',
                    pre_params: '',
                    dialogFormVisible: false,
                    formLabelWidth: '120px',
                    form: {},
                    tableData: [],

                    // 分页配置
                    pageSettings: {
                        // 分页配置
                        // 默认显示第几页
                        currentPage: 1,
                        // 总条数,根据接口获取数据长度(注意:这里不能为空)
                        totalCount: 1,
                        // 个数选择器(可修改)
                        pageSizes: [3, 5, 10, 20],
                        // 默认每页显示的条数(可修改)
                        PageSize: 10,
                    },
                }
            },
            mounted() {
                this.getData()
            },
            methods: {
                // 实现全页面排序
                sortChange({ prop, order }) {
                    this.tableData.sort(this.compare(prop, order));
                },
                sortChange(column) {
                    this.pageIndex = 1; // 排序后返回第一页
                    if (column.order === "descending") {
                        this.tableData.sort((a, b) => b[column.prop] - a[column.prop]);
                    } else if (column.order === "ascending") {
                        this.tableData.sort((a, b) => a[column.prop] - b[column.prop]);
                    }
                },

                // 查询
                getData() {
                    let that = this;

                    axios({
                        method: 'get',
                        url: 'http://localhost:8888/query',
                        params: {
                            name: that.input
                        }
                    }).then(
                        function (res) {
                            that.tableData = res.data;
                            console.log(that.tableData);

                            // 判断如果存在返回值,则将当前页改为1,否则无法显示内容
                            if (that.tableData.length > 0) {
                                that.pageSettings.currentPage = 1
                            }

                            // 将数据的长度赋值给totalCount
                            that.pageSettings.totalCount = that.tableData.length
                        }
                    ).catch(err => console.log(err))
                },

                // 功能_新增
                handleInsert(param) {
                    let that = this;

                    axios({
                        method: 'post',
                        url: 'http://localhost:8888/insert',
                        data: Qs.stringify({
                            id: that.id,
                            name: that.name,
                            note: that.note
                        })
                    }).then(
                        function (res) {
                            that.getData();
                            console.log(res);
                        }
                    ).catch(err => console.log(err));
                },

                // 功能_删除
                handleDelete(param) {
                    let that = this;

                    axios({
                        method: 'post',
                        url: 'http://localhost:8888/delete',
                        data: Qs.stringify({
                            id: param.row.id
                        })
                    }).then(
                        function (res) {
                            that.getData();
                            console.log(res.data);
                        }
                    ).catch(err => console.log(err));
                },

                // 功能_修改
                btn_edit(params) {
                    this.dialogFormVisible = true;
                    pre_params = params.row;
                    console.log(pre_params);

                    // 将被编辑行的原数据带入到编辑表单
                    this.form = {
                        id: pre_params.id,
                        name: pre_params.name,
                        note: pre_params.note
                    }
                },
                handleUpdate(params) {
                    let that = this;
                    console.log(params);

                    axios({
                        method: 'post',
                        url: 'http://localhost:8888/update',
                        data: Qs.stringify({
                            id: params.id,
                            name: params.name,
                            note: params.note,
                            pre_params: pre_params
                        })
                    }).then(
                        function (res) {
                            that.getData();
                            console.log(res.data);
                        }
                    ).catch(err => console.log(err));

                    this.dialogFormVisible = false;
                },

                // 分页
                // 每页显示的条数
                handleSizeChange(val) {
                    // 改变每页显示的条数 
                    this.pageSettings.PageSize = val
                    // 注意:在改变每页显示的条数时,要将页码显示到第一页
                    this.pageSettings.currentPage = 1
                },
                // 显示第几页
                handleCurrentChange(val) {
                    // 改变默认的页数
                    this.pageSettings.currentPage = val
                }
            }
        })
    </script>
    <style lang="">
        .membersTab {
            width: 800px;
            margin: 20px auto;
        }
    </style>
</body>

</html>

后端

js

// 使用expres框架,并创建应用
var express = require('express')
const app = express()

// 解决跨域请求
app.all('*', function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By", ' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
});

// 使用bodyParser中间件
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
    extended: true
}));

// 使用连接池,连接数据库
var mysql = require("mysql");
var pool = mysql.createPool({
    host: 'localhost',
    user: 'root',
    password: '123456',
    database: 'test'
});

// DMS.新增
app.post('/insert', (req, res) => {
    console.log('-------------------START INSERT---------------------');
    console.log(req.body);
    const sql = `insert into device(id,name,note) values('${req.body.id}','${req.body.name}','${req.body.note}')`;
    console.log(sql);

    pool.query(sql, (err, data) => {
        if (err) {
            console.log(err);
            res.send(err)
        } else {
            res.send(data)
        }
    })
    console.log('-------------------END INSERT---------------------');
})

// DMS.删除
app.post('/delete', (req, res) => {
    console.log('-------------------START DELETE---------------------');
    console.log(req.body);
    // 删除数据
    const sql = `delete from device where id = '${req.body.id}'`
    console.log(sql);

    pool.query(sql, (err, data) => {
        if (err) {
            console.log(err);
            res.send(err)
        } else {
            res.send(data)
        }
    })
    console.log('-------------------END DELETE---------------------');
})

// DMS.修改
app.post('/update', (req, res) => {
    console.log('-------------------START UPDATE---------------------');
    console.log(req.body);

    // 删除数据
    const sql = `update device set id = '${req.body.id}', name = '${req.body.name}', note = '${req.body.note}' where id = '${req.body.pre_params.id}'`
    console.log(sql);

    pool.query(sql, (err, data) => {
        if (err) {
            console.log(err);
            res.send(err)
        } else {
            res.send(data)
        }
    })
    console.log('-------------------END UPDATE---------------------');
})

// DMS.查询
app.get('/query', (req, res) => {
    console.log('-------------------START QUERY---------------------');
    console.log(req.query.name);

    // 判断输入框是否为空
    if (req.query.name == '' || req.query.name == undefined) {
        var sql = 'select * from device order by id'
    } else {
        // 可改为模糊查询
        // var sql = `select * from device where name = '${req.query.name}' order by id`
        var sql = `select * from device where name like '%${req.query.name}%' order by id`
    }
    console.log(sql);

    pool.getConnection((err, connection) => {
        connection.query(sql, function (err, data) {
            console.log(data)
            if (err) {
                console.log(err);
                return;
            }
            res.send(data)

            //释放连接
            connection.release();
            console.log('-------------------END QUERY---------------------');
        });
    });
})



// 端口必须要监听
app.listen(8888, () => {
    console.log("http://localhost:8888")
})



读取本地文件

// api请求:
// method: "get",
// url: "http://localhost:8081/query",
// params: {
//     filename: "input.txt",
// },

// 使用expres框架,并创建应用
const express = require('express');
const app = express();
const fs = require('fs');

// cors解决跨域问题
const cors = require('cors');
app.use(cors());

// 使用bodyParser中间件
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
    extended: true
}));

// 查询
app.get('/query', (req, res) => {
    var filename = req.query.filename;
    console.log(filename);

    // 规定格式:fs.readFile(filename, 'utf-8', (err, data) => {}),如果不指定'utf-8'将解析错误。
    fs.readFile(filename, 'utf-8', (err, data) => {
        if (err) {
            console.log(err);
            res.send(err);
        } else {
            console.log(data);
            res.send(data)
        }
    });
})

// 端口必须要监听
app.listen(8080, () => {
    console.log("http://localhost:8080")
})



常见问题处理

跨域问题

使用cors跨域

const cors = require('cors');
app.use(cors());

手动配置

首先,需要定义app,通过express框架

var express = require('express')
const app = express()

解决跨域接收请求

//设置跨域请求
app.all('*', function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By", ' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
});

解决跨域返回

// 使用中间件 允许跨域
// app.use(path,中间件函数)
app.use('/', (req, res, next) => {
    // 注意, 需要带 '*'
    res.set('Access-Control-Allow-Origin', '*');        
    next();
});


异步等待

即promise()函数的 async / await 用法。

await必须用在async标记的函数内部。

使用示例如下:

async function write() {
    console.log(1);
    
    // 写法1
    // await new Promise(function(resolve, reject) {
    //     setTimeout(function() {
    //         console.log(2);
    //         resolve(0);
    //     }, 2000);
    // });
    
    // 写法2
    var res = await new Promise((resolve, reject) => {
        setInterval(() => {
            resolve(2)
        }, 1000);
    })
    console.log(res);
    
    console.log(3);
}

write()
// 输出结果:
// 1
// 2 (1s后执行)
// 3

正常情况依次打印三个数字,由于2被设置了延时,所以应该最后打印2。

但是在使用了 async / await 之后,函数执行顺序必须等待打印2完成后才会执行后续。



res的各方法之间的区别

res.wirte()

必须和res.end()成对出现

res.write() 负责向前端返回数据,res.end() 负责结束请求。如果没有 res.end(),浏览器将会一直处于请求状态。

数据不做处理,原封不动返回

res.write()的返回数据是没有经过处理的,原封不动的返回原数据,所见即所得。

在结束浏览器响应请求之前,允许多次调用

使用 res.write() 可以输出多条语句,即在res.end() 之前可以执行多次,且返回的数据会被拼接到一起。

只允许输出字符串类型和Buffer对象两种数据类型

例如,如果输出数字则会报错。


res.send()

数据会被处理

会自动发送更多的响应报文头,包括返回数据类型,所以不会有乱码。

只允许调用一次

即等同于 res.write() + res.end()

支持多种内容格式

允许String、Array、Buffer对象、对象、json等。


res.json()

同 res.send(),响应结果都是json。



解析参数失败

引入 body-parser 模块,作为中间件

var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
    extended: true
}));
<think>好的,用户让我介绍一下Node.js常见知识,我需要整理一个清晰的结构,确保涵盖主要方面。首先,我应该从Node.js的基本定义开始,解释它是什么,它的核心特点,比如基于Chrome V8引擎、事件驱动、非阻塞I/O模型。这样用户能有一个初步的理解。 接下来,需要讨论Node.js的适用场景,比如高并发、I/O密集型应用,还有它不太适合CPU密集型任务。这部分需要对比传统服务端语言,比如PHP或Java,说明Node.js的优势和劣势,这样用户能知道何时选择它。 然后,模块系统是Node.js的重要组成部分,应该介绍CommonJS模块化,如何用require和module.exports来导入导出模块,以及ES6模块的支持情况。可能还要提到内置的核心模块,如fs、http、path等,以及npm的作用,这样用户了解模块化管理的方法。 异步编程是关键部分,需要详细说明回调函数、Promise、async/await,以及事件循环机制。这里要强调回调地狱的问题,以及如何用Promise和async/await来优化代码结构。同时,事件循环的几个阶段需要简单解释,帮助用户理解异步执行的原理。 常用框架和工具也是用户关心的,Express和Koa作为Web框架,Nest.js的现代化特性,Socket.IO处理实时通信,PM2用于进程管理,这些都是常用的工具,应该列举并简要说明它们的作用。 调试和性能优化方面,内置调试器、Chrome DevTools、以及常用的性能分析工具如clinic.js和node-inspector需要提到。性能优化策略如避免阻塞操作、使用集群、缓存等,都是实际开发中需要注意的点。 最后,要提到学习资源,官方文档、npm官网、Stack Overflow、中文社区如CNode,帮助用户进一步自学。可能还要补充一些常见问题,比如单线程的限制,如何处理CPU密集型任务,错误处理的最佳实践,安全注意事项,版本管理的重要性等。 在整理这些内容时,要注意语言简洁,结构清晰,避免使用过于专业的术语,或者必要时给出解释。同时,结合用户可能的实际需求,比如开发Web应用、API服务,或者工具脚本,来举例说明Node.js的应用场景,这样用户更容易理解。需要检查是否有遗漏的重要知识点,比如事件循环的各个阶段,或者最新的ES模块支持情况,确保信息的准确性和时效性。可能还需要提醒用户注意版本差异,比如Node.js的LTS版本和当前版本的区别,以及npm包的安装和管理技巧。总之,目标是提供一个全面而易于理解的Node.js介绍,帮助用户快速掌握核心概念和常见用法。Node</think>.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境,专为高性能、高并发的服务器端应用设计。以下是其核心知识点和常见应用场景的整理: --- ### **一、核心特点** 1. **非阻塞 I/O (异步模型)** - 通过事件循环(Event Loop)处理并发请求,避免线程阻塞。 - 适合 I/O 密集型场景(如文件读写、网络请求)。 2. **单线程与事件驱动** - 主线程处理事件回调,通过异步操作实现高并发。 - CPU 密集型任务可能成为性能瓶颈(需用子进程或 Worker Threads 优化)。 3. **模块化系统** - 基于 CommonJS 规范,使用 `require()` 和 `module.exports` 管理模块。 - 支持 ES6 模块(需 `.mjs` 扩展名或 `package.json` 配置)。 4. **NPM 生态** - 全球最大的开源库生态系统(如 `express`、`lodash`、`axios` 等)。 - 通过 `npm install` 管理依赖。 --- ### **二、适用场景** 1. **API 服务** - 快速构建 RESTful API(常用框架:Express、Koa、Fastify)。 2. **实时应用** - 聊天应用、在线协作工具(结合 WebSocket,如 `socket.io`)。 3. **微服务架构** - 轻量级、低资源消耗,适合容器化部署(如 Docker + Kubernetes)。 4. **工具链开发** - 构建工具(Webpack、Babel)、脚本工具等。 --- ### **三、核心模块** 1. **内置模块** - `fs`:文件系统操作。 - `http`/`https`:创建 HTTP 服务器。 - `path`:处理文件路径。 - `events`:事件触发器(如 `EventEmitter`)。 - `child_process`:创建子进程。 2. **常用第三方库** - `Express`:轻量级 Web 框架。 - `Sequelize`/`Mongoose`:数据库 ORM/ODM。 - `Axios`:HTTP 客户端。 - `PM2`:进程管理工具(日志、集群、热更新)。 --- ### **四、异步编程模式** 1. **回调函数(Callback)** - 基础异步模式,但易导致“回调地狱”。 ```javascript fs.readFile('file.txt', (err, data) => { if (err) throw err; console.log(data); }); ``` 2. **Promise** - 链式调用解决回调嵌套问题。 ```javascript fs.promises.readFile('file.txt') .then(data => console.log(data)) .catch(err => console.error(err)); ``` 3. **Async/Await** - 以同步写法处理异步操作(需配合 `try/catch`)。 ```javascript async function readFile() { try { const data = await fs.promises.readFile('file.txt'); console.log(data); } catch (err) { console.error(err); } } ``` --- ### **五、性能优化技巧** 1. **避免阻塞主线程** - 将 CPU 密集型任务交给子进程或 Worker Threads。 2. **使用集群模式** - 利用多核 CPU(如 `cluster` 模块或 PM2 集群)。 3. **缓存机制** - 使用 Redis 或内存缓存减少重复计算。 4. **代码优化** - 避免同步方法(如 `fs.readFileSync`)。 - 使用流(Stream)处理大文件。 --- ### **六、常见问题** 1. **如何处理 CPU 密集型任务?** - 使用 `worker_threads` 模块或拆分为独立微服务。 2. **如何调试 Node.js 应用?** - 内置调试器(`node inspect`)、Chrome DevTools 或 VS Code 调试插件。 3. **如何保证应用稳定性?** - 使用 PM2 守护进程、配置日志轮转、监控内存泄漏。 --- ### **七、学习资源** - **官方文档**:[nodejs.org](https://nodejs.org/) - **中文社区**:[CNode](https://cnodejs.org/) - **在线课程**:Udemy、慕课网的 Node.js 实战教程。 --- 掌握这些核心知识后,可结合具体项目实践(如搭建 API 服务、开发 CLI 工具)深化理解。遇到问题时,善用 NPM 生态和社区资源是关键!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值