node.js从入门到实践

node.js

node.js是前端最流行的javascript运行环境

  • node.js 是一个基于 chrome v8 引擎的 javascript 运行环境
  • node.js 使用了一个事件驱动、非阻塞式 I/O 模型,使其轻量又高效
  • node.js 的管理包 npm 是全球最大的开源库生态系统

node-v8引擎

javascript 引擎

  • 电脑根本不识别也不理解javascript
  • javascript 引擎起到的作用就是让电脑识别js代码

V8引擎

  • node.js是使用c++写的
  • V8引擎是Node.js的核心
  • V8引擎的作用是让JS代码能够让电脑识别

Module & Require

  • 在node.js中,文件和模块是一一对应的(每个文件被视为一个独立的模块)
//app.js文件引入stuff模块并应用
//requrie
let stuff = require('./stuff')
console.log(stuff.counter([1,2,3,4]));
console.log(stuff.adder(1,2));
console.log(stuff.pi);
//stuff模块
var counter = function (arr) {
    return '一共有' + arr.length + '个元素在数组中';
}


var adder = function (a,b) {
    return `您需要计算的两个值的和为:${a+b}`
}

var pi = 3.1415926;
//module
// module.exports.counter = counter;
// module.exports.adder = adder;
// module.exports.pi = pi;

module.exports = {
    counter: counter,
    adder: adder,
    pi: pi
}

事件模块

  • 大多数node.js核心API都是采用惯用的异步事件驱动架构(fs/http)
  • 所有能触发事件的对象都是EventEmitter类的实例
  • 事件流程:引入模块 -> 创建 EventEmitter 对象 -> 注册事件 -> 触发事件
//事件模块
//1.引入事件模块
var events = require('events');//引入系统模块,不要给定义的路径,直接给名字就可以了
//2.创建EventEmitter对象
var myEmitter = new events.EventEmitter();
//3.注册事件
myEmitter.on('someEvent',function (msg) {
    console.log(msg);
})
//4.触发事件
myEmitter.emit('someEvent','实现事件并传递此参数到注册事件的回调函数中')//事件名,参数
console.log(1); //先执行函数中内容,再执行打印1

如果想要函数异步执行,先执行打印1,再执行函数中内容的话可以这样修改

//事件模块
//1.引入事件模块
var events = require('events');//引入系统模块,不要给定义的路径,直接给名字就可以了
//2.创建EventEmitter对象
var myEmitter = new events.EventEmitter();
//3.注册事件
myEmitter.on('someEvent',function (msg) {
    // console.log(msg);

    //异步
    setImmediate(() => {
        console.log(msg);
    })
})
//4.触发事件
myEmitter.emit('someEvent','实现事件并传递此参数到注册事件的回调函数中')//事件名,参数
console.log(1); //先执行函数中内容,再执行打印1

文件系统模块

文件系统主要对项目中的文件进行操作

  • 读取文件(fs.readFile)
  • 写入文件(fs.writeFile)
  • 流程:引入fs模块 -> 调用方法 -> 异常捕获
//文件系统
//1.引入文件系统模块
var fs = require('fs');
//2.通过对象调用方法
//同步读取
var readMe = fs.readFileSync('./readMe.txt','utf8');//路径,文件格式
console.log(readMe);

//异步读取
var readMe2 = fs.readFile('./readMe.txt','utf8',function (err,data) {//路径,文件格式,回调函数(错误信息,返回值)
    if(err) throw err;
    console.log(data);
})
console.log(1);//先打印1,再打印读取信息

//同步写入
fs.writeFileSync('./writeMe.txt', readMe);//文件路径,写入内容

//异步写入
fs.readFile('./readMe.txt','utf8',function (err,data) {
    if(err) throw err;
    fs.writeFile('./writeMe2.txt',data);
})
  • 创建文件夹(fs.mkdir)
  • 删除文件夹(fs.rmdir)
  • 删除文件(fs.unlink)
  • 流程:引入fs模块 -> 调用方法 -> 异常捕获
//文件系统
//1.引入文件系统模块
var fs = require('fs');
//2.通过对象调用方法
// 删除文件
fs.unlink('./writeMe.txt',function (err) {
    if(err) throw err;
    console.log('文件删除成功!');
// });

//创建文件夹 同步
fs.mkdirSync('stuff');

//删除文件夹 同步
fs.rmdirSync('stuff');

//异步创建文件夹
fs.mkdir('stuff',function (err) {
    if(err) throw err;
    fs.readFile('readMe.txt','utf8',function (err2,data) {
        if(err2) throw err2;
        fs.writeFile('./stuff/writeMe.txt',data,function(){});
    })
})

//异步删除文件夹
// 1.删除文件夹中内容
// 2.再删除文件夹
fs.unlink('./stuff/writeMe.txt',function () {
    fs.rmdir('stuff', function (err) {
        if (err) throw err;
        console.log('文件夹删除成功!');
    })
})

注意事项

  • fs.writeFile(file, data[, options], callback)在v10.0之后回调函数为必选参数,否则会报错。
  • fs.writeFileSync(file, data[, options])没有回调函数

http创建服务器

node.js从入门到实践_第1张图片
客户端与服务端关系

client为客户端,好比用户看到的浏览器,server为服务器。当用户想要访问一个页面时,内部流程为:浏览器中是输入域名 地址www.baidu.com,该域名会绑定到某个服务器上,因为域名本身是没有数据展示的,绑定服务器后才会请求服务器,服务器才会返回对应的数据展示。所以客户端的作用就是用户输入一个域名地址,回车后发送网络请求到绑定的服务器,服务器再返回数据给客户端。

客户端与服务器对接的方式:

客户端想服务器方式请求时需要对应的ip地址或域名或服务器地址,当浏览器中输入地址回车后,通过http或https协议发送请求,请求过程中可以通过socket进行请求,请求到server后,如果网络、状态码等都是正常的话,就可以和server进行对接了。对接后server发现你的请求,需要返回对应的数据,服务端使用tcp协议返回客户端数据。

  • 通过Http模块创建本地服务器
//通过http模块,创建本地服务器
var http = require('http');

//创建服务器方法
var server = http.createServer(function (req,res) {
    console.log('客户端向服务器发送请求:' + req.url);
    res.writeHead(200,{"Content-type":"text/plain"});
    res.end('Server is working!');
})

//服务对象监听服务器地址和端口号
server.listen(8888,"127.0.0.1");
console.log('server is running...')

Buffer & Stream

  • buffer 可以在TCP流和文件系统操作等场景中处理二进制数据流。


    node.js从入门到实践_第2张图片
    缓存区

buffer,即缓存区。服务器向客户端返回数据时采用的是tcp协议,在返回过程中有TCP的流,在JS中没有二进制流的说法,但在node.js中,为了能拥有一个缓存区,使用buffer。

Buffer 类在全局作用域中,因此无需使用 require('buffer').Buffer。

在引入 TypedArray 之前,JavaScript 语言没有用于读取或操作二进制数据流的机制。 Buffer 类是作为 Node.js API 的一部分引入的,用于在 TCP 流、文件系统操作、以及其他上下文中与八位字节流进行交互。


  • 在node.js中是处理流数据的抽象接口


    node.js从入门到实践_第3张图片
  • 管道事件 改变流的走向
    左面输出 | 右面输入


    node.js从入门到实践_第4张图片
    管道事件
let fs = require('fs');
//读取数据流
let myReadStram = fs.createReadStream(__dirname + '/readMe.txt','utf8');
// console.log(myReadStram);


//写入文件流
let myWriteStram = fs.createWriteStream(__dirname + '/writeMe.txt');
//再没有填充内容到流中时,文件夹中不会新建对应的文件


let times = 0;
myReadStram.on('data',(chunk) => {
    times++;
    console.log('===================正在接收'+ times +'一部分数据========================')
    // console.log(chunk);
    //写入数据
    myWriteStram.write(chunk);
});
//data为服务器返回数据必须触发的方法,且为约定俗成的,不可改变;
//返回的数据将以回调函数返回,数据为小块小块的返回
//读取数据时,也会经过缓存区,放到缓存区后再以流的形式展现给我们
let fs = require('fs');
//读取数据流
let myReadStram = fs.createReadStream(__dirname + '/readMe.txt','utf8');
// console.log(myReadStram);


//写入文件流
let myWriteStram = fs.createWriteStream(__dirname + '/writeMe2.txt');
//再没有填充内容到流中时,文件夹中不会新建对应的文件

//pipe通过管道流入到可写流的来源流。
myReadStram.pipe(myWriteStram);//拿到的数据调用了,参数为输入数据目的地
//通过pipe写入浏览器
let http = require('http');
let fs = require('fs');


//搭建服务器
let server = http.createServer((req,res) => {
    console.log(req);
    res.writeHead(200,{"Content-type":"text/plain"});
    let myReadStram = fs.createReadStream(__dirname + '/readMe.txt','utf8');
    myReadStram.pipe(res);
})

server.listen(9999,'127.0.0.1');
console.log('服务启动!');

读取HTML和JSON

let http = require('http');
let fs = require('fs');


//搭建服务器
let server = http.createServer((req,res) => {
    //console.log('客户端向服务器发送请求:' + req.url);
    //客户端向服务器发送请求:/               请求127.0.0.1:9999接口
    //客户端向服务器发送请求:/favicon.ico         请求标签栏的logo

    if(req.url !== '/favicon.ico'){
        console.log('客户端向服务器发送请求:' + req.url);
        //打印一遍
        //客户端向服务器发送请求:/               请求127.0.0.1:9999接口

        // res.writeHead(200,{"Content-type":"text/plain"});//数据类型:纯文本
        res.writeHead(200,{"Content-type":"text/html"});//数据类型:html
        // res.writeHead(200,{"Content-type":"application/json"});//数据类型:json


        // let myReadStram = fs.createReadStream(__dirname + '/readMe.txt','utf8');
        let myReadStram = fs.createReadStream(__dirname + '/index.html','utf8');
        // let myReadStram = fs.createReadStream(__dirname + '/perrson.json','utf8');

        myReadStram.pipe(res);
    }
})

server.listen(9999,'127.0.0.1');
console.log('服务启动!');

route 路由

路由既是“路在何方”

let http = require('http');
let fs = require('fs');


//搭建服务器
let server = http.createServer((req,res) => {
    if(req.url !== '/favicon.ico'){
        //判断用户所访问的页面地址
        if(req.url == '/home' || req.url == '/'){
            res.writeHead(200,{"Content-type":"text/html"});//数据类型:html
            fs.createReadStream(__dirname + '/index.html').pipe(res);
        }else if(req.url == '/contact'){
            res.writeHead(200,{"Content-type":"text/html"});//数据类型:html
            fs.createReadStream(__dirname + '/contact.html').pipe(res);
        }else if(req.url == '/api/docs'){
            // res.writeHead(200,{"Content-type":"text/html"});//数据类型:html
            // fs.createReadStream(__dirname + '/api/docs.html').pipe(res);

            var data = [
                {
                    name:'andy',
                    age:30
                },
                {
                    name:'qiongqiong',
                    age:16
                },
            ]
            res.writeHead(200,{"Content-type":"application/json"});//数据类型:json
            res.end(JSON.stringify(data));
        }
    }
})

server.listen(9999,'127.0.0.1');
console.log('服务启动!');

NPM_Package

  • npm : 是随同NodeJs一起安装的管理工具,能解决NodeJs 代码部署上的很多问题

常用的使用场景:

  • 允许用户从NPM服务器下载别人编写的第三方包到本地使用
  • 允许用户从NPM服务下载并安装别人编写的命令行程序到本地使用
  • 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用

安装模块:$ npm install 模块名

  • package : 用于定义项目中所需的各种模块,以及项目的配置信息(比如名称,版本,许可证等元数据)
    安装package :在项目文件夹中npm init运行,再根据自己的需求进行配置即可。

只有当项目文件夹中有package.json文件时才 可以使用npm install来安装模块依赖,安装的依赖会保存在node_modules文件夹中

卸载模块:npm uninstall 模块名

{
  "name": "nodedemo",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "jquery": "^3.4.0"//npm install XXX --save  保存记录
  },
  "devDependencies": {
    "express": "^4.16.4" //npm install XXX --save-dev  保存记录
  }
}

Experss 框架介绍及安装

基于Node.js平台,快速、开发、极简的web开发框架。

  • 安装 npm install express --save

nodemon工具

在开发环境下,往往需要一个工具来自动重启项目工程,我们可以借助nodemon来替代node进行启动

  • 安装npm install -g nodemon --save-dev
  • 运行 使用命令nodemon 文件名
    node.js从入门到实践_第5张图片
    运行成功

Experss 框架

Experss 能做什么

  • 已经封装好服务器
  • 已经封装好路由
  • 已经封装好中间件
  • 已经封装好网络请求...

使用方法:

  1. npm 安装 Express 框架
  2. 引入 Express 模块
  3. 实例化 Express 对象
  4. 通过对象进行调用各种方法
//引入express模块
var express = require('express');

//实例化express的对象
var app = express();

//通过对象调用对应的方法

//根据用户请求的地址,返回对应的数据信息
app.get('/',function (req,res) {
    console.log(req.url)
    res.send('这是首页!')
})

app.get('/contact',function (req,res) {
    console.log(req.url)
    res.send('这是联系我们!')
})

//路由参数
//路由参数之后只能有一个斜杠
//例:http://127.0.0.1:8888/profile/list1201   ,返回的就是list1201;而http://127.0.0.1:8888/profile/list1201/ss 就显示‘Cannot GET /profile/list1201/ss’
app.get('/profile/:id',function (req,res) {
    res.send('您所访问的路径参数为'+ req.params.id);
})

//监听服务器端口号
app.listen(8888);

EJS模板引擎

ESJ模板引擎的特点

  1. 快速编译和渲染
  2. 简单的模板标签
  3. 支持浏览器端和服务器端
  4. 支持express视图系统

安装
npm install ejs --save-dev

//引入 express 模块
var express = require('express');
//实例化 Express 对象
var app = express();
app.set('view engine','ejs');  //配置视图引擎使用ejs
//通过对象调用方法
//路由参数
 app.get('/profile/:id',function (req,res) {
   //   res.send('你所访问的路径为:'+ req.params.id);//返回路由参数
   res.sendFile(__dirname + '/views/profile.ejs');//不配置视图引擎时,访问页面,会将对应的文件下载下来
   res.render('profile',{name:'LALALA'});//渲染ejs页面   参一:渲染对应的文件  参二:传递的数据 在对应的文件中使用 ‘

欢迎来到 <%=name %> 网页!

来接收’ }) //监听服务器端口号 app.listen(8888);
//引入 express 模块
var express = require('express');
//实例化 Express 对象
var app = express();
app.set('view engine','ejs');  //配置视图引擎使用ejs
//通过对象调用方法

//根据用户请求地址,返回对应的数据信息
app.get('/',function (req,res) { //当访问根路径时,返回‘这是首页!’
    console.log(req.url);//打印路径
    res.sendFile(__dirname + '/index.html');//返回对应的html文件
 })

 app.get('/contact',function(req,res){
    res.sendFile(__dirname + '/contact.html');
 })

 //路由参数
 app.get('/profile/:id',function (req,res) {
   // let data = {age:23,name:'andy'};
   // let data = [{age:23,name:'andy'},{age:26,name:'kitty'},{age:24,name:'jack'}];
   let data = [{age:23,name:['张三','李四']},{age:26,name:['王五','赵六']},{age:24,name:['傻大个','胖子']}];
   res.render('profile',{websiteName:req.params.id,data:data})
  })

//监听服务器端口号
app.listen(8888);

以上代码data分别对应的渲染为

//let data = {age:23,name:'andy'};

年龄:<%= data.age %>

姓名:<%= data.name %>

// let data = [{age:23,name:'andy'},{age:26,name:'kitty'},{age:24,name:'jack'}];
    <% data.forEach((item) => {%>
  • 年龄: <%= item.age%>
  • 姓名: <%= item.name%>
  • <% })%>
//<%%>标签必须每行都需要闭合,如遇到代码换行时,必须将每行都用<% %>包裹
//let data = [{age:23,name:['张三','李四']},{age:26,name:['王五','赵六']},{age:24,name:['傻大个','胖子']}];
    <% data.forEach((item) => {%>
  • 年龄: <%= item.age%>
  • 姓名: <% item.name.forEach((item2) => { %> <%= item2%> <%}) %>
  • <% })%>

公共模板

  • 使用EJS文件替换HTML文件
  • 创建导航(公共模板)
  • 解决外部样式不可用问题

将html页面全部使用ejs文件进行开发,文件结构可以参考以下


node.js从入门到实践_第6张图片
文件结构
  • 一般页面视图放在views文件夹中
  • 封装的公共模块放在public文件夹中
  • 静态资源放在assers文件夹中

将封装好的公共模块引入到对应的页面即可正常渲染


<% include ../public/nav.ejs%>

在页面中引入外部样式时,需要先在app.js中进行配置,方可引用

//app.js
//让服务器识别外部样式表
app.use('/assets',express.static('assets'));
//参一:路径  参二:该路径文件做什么事
//此时的参二表示:在项目中,让css静态文件转化为模块化,让服务器进行识别。否则加载样式表会报错
//各文件中正常引用

实战操作 ToDoApp

启动新项目
初始化webpack
安装express框架
安装esj body-parser 模块

  1. 新建项目文件夹TodoApp,并在该文件夹中安装 package npm init
  2. 安装express 框架 npm install express --save-dev
  3. 安装 ejs 和 body-parser 模块 npm install ejs body-parser --save-dev
  4. 在项目文件夹中创建主文件的入口app.js
  5. 新建controller文件夹并添加todoController.js文件来处理项目中对应的逻辑
  6. 新建public文件夹来写入对应的样式
//app.js
let express = require('express');//引入express

let todoController = require('./controller/todoController')//自定义模块todoController
let app = express();//实例化express对象
app.set('view engine','ejs');//配置视图渲染规则按照ejs渲染

// app.use('/public',express.static('public'))
//等同于
app.use(express.static('./public'))//配置静态资源模块化,让浏览器识别

todoController(app)

app.listen(3000)//监听端口号
//todoController.js
module.exports = function (app) {
    //获取数据
    app.get('/todo', (req,res) => {
        res.send(req.url);
     })

     //传递数据
     app.post('/todo',(req,res) => {
        //coding...
     })

     //删除数据
     app.delete('/todo',(req,res) => {
         //coding
     })
 }

引入jquery
设置视图
设置请求页面返回视图
设置视图样式

  1. 在项目文件夹中新建views文件夹并添加todo.ejs文件并完成静态页面布局
  2. 将todoController.js文件修改,设置请求页面返回视图
//获取数据
  app.get('/todo', (req,res) => {
        res.render('todo');
     })

在控制器中处理本地数据
在视图上将数据展示出来
最终的代码以及样式展示

//todoController.js

let bodyParser = require('body-parser');
//对数据进行解析
let urlencodeParser =  bodyParser.urlencoded({extended:false});

let data = [
    {item:'欢迎大家来到茕茕课堂练习!'},
    {item:'希望大家能喜欢我的练习!'},
    {item:'一个个手敲代码好累哦!'},
]

//todoController
module.exports = function (app) {
    //获取数据
    app.get('/todo', (req,res) => {
        res.render('todo',{todos:data});
     })

     //传递数据
     app.post('/todo',urlencodeParser,(req,res) => {
        //coding...
        console.log(req.body);
        data.push(req.body);
     })

     //删除数据
     app.delete('/todo/:item',(req,res) => {
         //coding
         console.log(req.params.item);
         data = data.filter(function (todo) {
            return req.params.item != todo.item;
          })

          res.json(data);
     })
 }
//todo.ejs



    
    
    
    todoApp
    
    
    
    


    
    <% todos.forEach((val,ind) => {%>
  • <%= val.item%>
  • <% })%>
  • 邓伦最帅!

因为主要为node.js的学习,此处的样式省略,之后会抛出代码提供参考。


node.js从入门到实践_第7张图片
最终页面样式展示

mongoose

安装mongoose模块
使用mongoDB网络数据库
创建数据库及配置用户名及密码
链接mongoDB数据库

  1. 安装mongoose npm install mongoose --save-dev
  2. 在mongodb 官网注册账号并新建配置数据库
  3. 链接数据库,在 todoController.js 文件中引入并替换之前的方法

npm root -g 获取全局安装依赖路径

//todoController.js
//引入mongoose 模块
let mongoose = require('mongoose');
//链接数据库
mongoose.connect('mongodb+srv:*******************',{useNewUrlParser:true})
//创建图表
let todoSchema  = new mongoose.Schema({
   item:String
})

//往数据库中存储数据
let Todo = mongoose.model('Todo',todoSchema);

//测试存储
// Todo({item:'大家好'})
//     .save((err,data) => {
//         if(err) throw err;
//         console.log('保存成功!')
//     })

let bodyParser = require('body-parser');
//对数据进行解析
let urlencodeParser =  bodyParser.urlencoded({extended:false});

// let data = [
//     {item:'欢迎大家来到茕茕课堂练习!'},
//     {item:'希望大家能喜欢我的练习!'},
//     {item:'一个个手敲代码好累哦!'},
// ]

//todoController
module.exports = function (app) {
   //获取数据
   app.get('/todo', (req,res) => {
       // res.render('todo',{todos:data});
       Todo.find({},(err,data) => {
           if(err) throw err;
           res.render('todo',{todos:data});
       })

    })

    //传递数据
    app.post('/todo',urlencodeParser,(req,res) => {
       //coding...
       // console.log(req.body);
       // data.push(req.body);

       Todo(req.body)
           .save((err,data) => {
               if(err) throw err;
               res.json(data);
           })
    })

    //删除数据
    app.delete('/todo/:item',(req,res) => {
        //coding
       //  console.log(req.params.item);
       //  data = data.filter(function (todo) {
       //     return req.params.item != todo.item;
       //   })

       //   res.json(data);

       Todo.find({item:req.params.item})
           .remove((err,data) => {
               if(err) throw err;
               res.json(data);
           })
    })
}

至此,todoApp的实战已经到达尾声,我们已经完成链接线上数据库获取数据、添加数据,查找数据并删除的功能。剩下的完成功能就当做家庭小作业吧O(∩_∩)O哈哈~
源码附上

你可能感兴趣的:(node.js从入门到实践)