151.Node.js学习笔记(五)2018.12.16

7 篇文章 0 订阅
7 篇文章 0 订阅

快捷键
Ctr+Shift+左键、右键、上键、下键 等于选中
Ctr+D 选中相邻的单词

0. 知识点

  • MongoDB

    • 安装
    • MongoDB的可视化工具MongoBooster
    • 基本命令
    • Node当中使用MongoDB
    • CRUD案例改写为MongoDB数据库
  • Mongoose

  • Node操作MySQL数据库

  • Promise

  • 回调地狱

1. 反馈

  • 回调函数
    • 异步编程
    • 如果得到一个函数内部异步操作的结果,这时候必须通过回调函数来获取
    • 在调用的位置传递一个函数进来
    • 在封装的函数内部调用传递进来的函数
  • callback是不是相当于函数自调用?
    • 很简单,函数也是一种数据类型,既可以当作参数进行传递,也可以当作方法的返回值
    • 一般情况下,把函数作为参数的目的就是为了获取函数内部的异步操作结果
    • JavaScript 涉及到底层原理:单线程、事件循环
    • 注意:凡是需要得到一个函数内部异步操作的结果,setTimeout,readFile,writeFile
    • 这种情况必须通过:回调函数
  • 示例1:
console.log(‘1’) 
setTimeout(function(){ 
console.log(‘2’) 
},0) 
console.log(‘3’) 
// 执行结果:任何时候都是1,3,2,因为JS的单线程、事件循环机制
  • 示例2:
// 不成立的情况: 
function add(x, y){ 
console.log(1) 
setTimeout(function(){ 
console.log(2) 
var ret = x + y 
return ret 
},1000) 
console.log(3) 
// 到这里执行结束,不会等到前面的定时器,所以直接就返回默认值undefined 
// 输出结果:1、3、 undefined、2 
} 
console.log(add(10,20)) // => undefined
  • 示例3:
// 不成立的情况 
function add(x, y){ 
var ret // 定义变量ret,但未赋值:undefined
console.log(1) 
setTimeout(function(){ 
console.log(2) 
ret = x + y 
},1000) 
console.log(3) 
return ret 
// 输出结果:1、3、undefined、2
} 
console.log(add(10,20)) // => undefined
  • 示例4: 回调函数
  • 这是javascript编程的一大特色,异步编程
    在这里插入图片描述

注意:a是形参、ret是实参
返回的结果:1、30

  • 我们现在用的模块化是CMD吧 ?能不能扩展一下AMD?

    • PHP 中为什么就可以直接 require、include ?因为 PHP 当初在设计的时候就加入了这个功能
    • PHP 这门语言天生就支持
    • 模块作用域
    • 可以使用 API 来进行文件与文件之间的依赖加载
    • 在 Node 这个环境中对 JavaScript 进行了特殊的模块化支持 CommonJS
    • JavaScript 天生不支持模块化
      • require
      • exports
      • Node.js 才有的
    • 在浏览器中也可以像在 Node 中的模块一样来进行编程
      • script标签来引用加载,而且你还必须考虑加载的顺序问题
      • require.js 第三方库 AMD
      • sea.js 第三方库 CMD
    • 无论是 CommonJS、AMD、CMD、UMD、EcmaScript 6 Modules 官方规范
      • 都是为了解决 JavaScript 的模块化问题
      • CommonJS、AMD、CMD 都是民间搞出来的
      • EcmaScript 是官方规范定义
      • 官方看民间都在乱搞,开发人员为了在不同的环境使用不同的 JavaScript 模块化解决方案
      • 所以 EcmaScript 在 2015 年发布了 EcmaScript 2016 官方标准
      • 其中就包含了官方对 JavaScript 模块化的支持
      • 也就是说语言天生就支持了
      • 但是虽然标准已经发布了,但是很多 JavaScript 运行换将还不支持
      • Node 也是只在 8.5 版本之后才对 EcmaScript 6 module 进行了支持
      • 后面学 Vue 的时候会去学习
      • less 编译器 > css
      • EcmaScript 6 -> 编译器 -> EcmaScript 5
      • 目前的前端情况都是使用很多新技术,然后利用编译器工具打包可以在低版本浏览器运行。
      • 使用新技术的目的就是为了提高效率,增加可维护性
  • var router = require(’./router’) 这一步不是加载router.js并执行该文件吗 为什么还要执行app.use(router) app.use 不是开放静态资源吗 app.use(router)在这里是什么意思,挂载到 app 服务中的意思是? module.exports = app 也不懂

    • 这里涉及到一个中间件的概念
    • app.use 不仅仅是用来处理静态资源的
    • 还可以做很多工作
    • 配置 body-parse 也是通过 app.use 来配置的
    • 这叫中间件,其中有一套规则
  • npm init --yes 生成一个package.json 文件 npm --save 文件名 又生成一个package-lock.json文件,又生成的文件和初始化生成的文件有区别吗?

    • 当你安装包的时候,新版的 npm 还会自动生成一个文件:package-lock.json
  • 为什么模板引擎在app.js中引入之后在router.js中不引入可以直接使用,而express还需要在router.js中再引入一次 app.js中路由器挂载不是很懂 router.js中为什么要创建一个路由器容器,不知道作用是干什么的 es6中的find方法不是很懂

    • 中间件
    • ECMAScript 6 的 find 方法
  • find/findIndex

    • find接收一个方法作为参数,方法内部返回一个条件
    • find会遍历所有的元素,执行你给定的带有条件返回值的函数
    • 符合该条件的元素作为find方法的返回值
    • 如果遍历结束还没有找到符合条件的元素,则返回undefined

2. MongoDB

2.1 关系型数据库和非关系型数据库

  • 表就是关系
  • 或者说表与表之间存在关系
  • 所有的关系型数据库都需要通过sql语言来操作
  • 所有的关系型数据库在操作之前都需要设计表结构
  • 而且数据表还支持约束
    • 唯一的
    • 主键
    • 默认值
    • 非空
  • 非关系想数据库非常的灵活
  • 有的非关系型数据库就是key-value对
  • 但是MongoDB是长得最像关系型数据库的非关系型数据库
  • 在MongoDB中:
    • 数据库 还叫 数据库
    • 数据库 叫 集合(数组)
    • 表记录 叫 文档对象)
    • MongoDB是不需要设计表结构
    • 也就是说可以任意的往里面存数据,没有结构性这么一说

2.2 安装

2.3 启动和关闭数据库

  • 启动

// mongodb 默认使用执行 mongod 命令所在盘符根目录下的/data/db作为自己的数据存储目录
// 所以在第一次执行该命令之前先自己手动新建一个 /data/db
// 启动命令:mongod

  • 注意:如果没有/data/db目录,会报错信息如下:

  • “shutting down with code 100”
    在这里插入图片描述

  • 此时,在C盘根目录下,新建data/db目录,即可
    在这里插入图片描述

  • 再次启动,必须先关闭上次打开的cmd窗口,才能启动成功
    在这里插入图片描述

  • 如果想要修改默认的数据库存储目录,可以:

mongod --dbpath=数据存储目录路径

  • 但是,这种方式过于麻烦,不推荐使用
  • 停止

在开启服务的控制台,直接Ctrl+C即可停止。
或者
直接关闭开启服务的控制台也可以。

2.4 连接和退出数据库

  • 连接

// 该命令默认链接本机的 MongoDB服务
mongo

  • 退出

// 在连接状态输入 exit 退出连接
exit

2.5 基本命令

  • show dbs
    • 查看显示所有数据库
  • db
    • 查看当前操作的数据库
  • use 数据库名称
    • 切换到指定的数据(如果没有会新建)
  • 插入数据
    • db.students.insertOne({“name”:”jack”})
  • 显示当前db 的所有集合
    • show collections
  • 查询当前db的所有数据
    • db.students.find()

2.6 在Node中如何操作MongoDB数据库

示例1:

 // 引包 
var mongoose = require(‘mongoose’); 
mongoose.connect(‘mongodb://localhost/test’, { useMongoClient: true }); 
mongoose.Promise = global.Promise;

var Cat = mongoose.model(‘Cat’, { name: String }); 
// 连接 MongoDB 数据库 
// 指定连接的数据库不需要存在,当你插入第一条数据之后就会自动被创建出来 

// 创建一个模型,就是在设计数据库 
// MongoDB是动态的,非常灵活,只需要在代码中设计你的数据库就可以了 
// mongoose这个包可以让你的设计编写过程变得非常简单 

// 实例化一个Cat 
var kitty = new Cat({ name: ‘Zildjian’ }); 

// 持久化保持kitty实例 
 kitty.save(function (err) {
    if (err) {
      console.log(err);
    } else {
      console.log('meow');
    }
  });

示例2:
循环插入100条数据

var mongoose = require('mongoose');

// 连接 MongoDB 数据库
mongoose.connect('mongodb://localhost/test', { useMongoClient: true });

mongoose.Promise = global.Promise;

// 创建一个模型
// 就是在设计数据库
// MongoDB 是动态的,非常灵活,只需要在代码中设计你的数据库就可以了
// mongoose 这个包就可以让你的设计编写过程变的非常的简单
var Cat = mongoose.model('Cat', { name: String });

for (var i = 0; i < 100; i++) {
  // 实例化一个 Cat
  var kitty = new Cat({ name: '喵喵' + i });

  // 持久化保存 kitty 实例
  kitty.save(function (err) {
    if (err) {
      console.log(err);
    } else {
      console.log('meow');
    }
  });
}

8.7 MongoDB数据库的基本概念

  • 数据库(可以有多个数据库)
  • 集合(一个数据库中可以有多个集合)
  • 文档(一个集合中可以有多个文档(表记录))
  • 文档结构很灵活,没有任何限制
  • MongoDB非常灵活,不需要像 MySQL一样先创建数据库、表、设计表结构
  • 在这里只需要:当你需要插入数据的时候,只需要指定往哪个数据库的哪个集合操作就可以了
  • 一起都由MongoDB来自动完成建库建表
{ 
 qq:{ 
   users:[ 
   {name: ‘张三’, age: 12}, 
   {name: ‘李四’, age: 22}
  { name: ‘王五’, age: 32}
   ...... 
  ], 
 products:[] 
   ......
 }, 
  taobao:{}, 
  baidu:{} 
}

2.8 官方指南

  • 设计Scheme发布Model
var mongoose = require('mongoose')
var Schema = mongoose.Schema
// 1. 连接数据库,默认的数据库端口是27017
// mongoose.connect('mongodb://localhost/27017');
// 连接本地的itcast数据库,该数据库可以不存在,但会自动创建itcast
mongoose.connect('mongodb://localhost/itcast');

// 2. 设计集合结构(表结构)
// 字段名称就是表结构中的属性名称
// 约束的目的是为了保证数据的完整性,不要有脏数据
var userSchema = new Schema({
    username: {
        type: String,
        required: true // 必须有
    },
    password: {
        type: String,
        required: true
    },
    email: {
        type: String
    }
});

// 3. 将文档结构发布为模型
// mongoose.model方法就是用来将一个架构发布为model

// 第一个参数:传入一个大写名词单数字符串用来表示你的数据库名称
// 例如这里的User最终会变为users集合名称

// 第二个参数:架构Schema
// 返回值:模型构造函数
var User = mongoose.model('User',userSchema)

// 4. 当我们有了一个模型构造函数之后,就可以使用这个构造函数对User集合中的数据为所欲为了
module.exports =User
  • 增加数据
var admin = new User({
    username: 'admin',
    password: '123345',
    email: 'admin@qq.com'
})

admin.save(function(err,ret){
    if(err){
        console.log('保存失败');
    }else{
        console.log('保存成功')
        console.log(ret)
    }
})
  • 查询

    • 查询所有
User.find(function(err,ret){
    if(err){
        console.log('查询失败')
    }else{
        console.log(ret)
    }
})
  • 按条件查询所有
User.find({
    username: '张三'
},function(err,ret){
    if(err){
        console.log('查询失败')
    }else{
        console.log(ret)
    }
})
  • 按条件查询单个数据
User.findOne({
    username: 'admin',
    password: 222
},function(err,ret){
    if(err){
        console.log('查询失败')
    }else{
        console.log(ret)
    }
})
  • 删除数据
User.remove({
    username: 'admin'
},function(err,ret){
    if(err){
        console.log('删除失败')
    }else{
        console.log('删除成功')
    }
})
// 根据条件删除一个
Model.findOneAndRemove(conditions,[options],[callback])
// 根据 id 删除一个
Model.findByIdAndRemove(id,[options],[callback])
  • 更新数据
// 根据条件更新所有
Model.update(conditions,doc,[options],[callback])
// 根据指定的条件更新一个
Model.findOneAndUpdate([conditions],[update],[options],[callback])
// 根据id
User.findByIdAndUpdate('5b78008cfd7edbd6beda079c',{
    password: '123'
},function(err,ret){
    if(err){
        console.log('更新失败')
    }else{
        console.log('更新成功')
    }
})

3. Node.js操作MySQL

3.1 安装mysql

先初始化,生成package.json文件:
npm init -y
然后安装mysql
npm i mysql
或者,使用淘宝镜像源
cnpm i mysql

3.2 使用案例

var mysql = require('mysql');

// 1. 创建连接
var connection = mysql.createConnection({
  host: 'localhost', // 主机地址,默认为localhost
  user: 'root', // 用户名
  password: 'root', // 密码
  database: 'sjk' // 数据库名称
});

// 2. 连接数据库,“打开冰箱门” 
connection.connect();

// 3. 执行数据操作,“ 把大象放到冰箱”
connection.query('SELECT * FROM `users`', function (error, results, fields) {
  if (error) throw error;
  console.log('The solution is: ', results);
});

// connection.query('INSERT INTO users VALUES(0, "admin", "123456")', function (error, results, fields) {
//   if (error) throw error;
//   console.log('The solution is: ', results);
// });

// 4. 关闭连接,“ 关闭冰箱门”
connection.end();

4. Promise

4.1 callback hell(回调地狱)

  • 下面的代码无法保证执行顺序
  • 输出结果顺序不一致,原因是操作系统的调度机制导致的
var fs = require('fs')

fs.readFile('./data/a.txt','utf8',function(err,data){
    if(err){
        // 抛出异常
        //     1. 阻止程序的执行
        //     2. 把错误消息打印到控制台
        throw err
    }
    console.log(data)
});

fs.readFile('./data/b.txt','utf8',function(err,data){
    if(err){
        throw err
    }
    console.log(data)
});

fs.readFile('./data/c.txt','utf8',function(err,data){
    if(err){
        throw err
    }
    console.log(data)
  • 通过回调嵌套的方式来保证顺序:
  • 带来的问题:语法丑陋、嵌套过深、维护困难
var fs = require('fs')

fs.readFile('./data/a.txt', 'utf8', function (err, data) {
  if (err) {
    // return console.log('读取失败')
    // 抛出异常
    //    1. 阻止程序的执行
    //    2. 把错误消息打印到控制台
    throw err
  }
  console.log(data)
  fs.readFile('./data/b.txt', 'utf8', function (err, data) {
    if (err) {
      // return console.log('读取失败')
      // 抛出异常
      //    1. 阻止程序的执行
      //    2. 把错误消息打印到控制台
      throw err
    }
    console.log(data)
    fs.readFile('./data/c.txt', 'utf8', function (err, data) {
      if (err) {
        // return console.log('读取失败')
        // 抛出异常
        //    1. 阻止程序的执行
        //    2. 把错误消息打印到控制台
        throw err
      }
      console.log(data)
    })
  })
})
  • 为了解决以上的编码方式带来的问题(回调地狱嵌套),所有ES6中新增了一个API
  • promise方法

4.2 Promise

  • Promise是一个构造函数

  • Promise容器,容器中存放了一个异步任务

  • Promise本身不是异步,但是内部默认都封装了一个异步任务

  • 这个异步任务分为三种状态:

    • pending:正在执行
    • resloved:已成功
    • rejected:已失败
  • 状态一旦改变,就无法再次改变状态

  • then方法获取容器的结果(成功的,失败的)

  • then(参数1,参数2)

    • 作用:为promise实例添加状态改变时的回调函数

    • 参数1:是成功的回调函数,参数2:是失败的回调函数

  • 返回值:then()方法返回的是一个新的promise实例

  • then方法支持链式调用

  • 可以在then方法当中返回一个promise对象,然后在后面的then方法中,获取上一个then返回的promise对象的状态结果。

  • Promise基本语法:

var fs = require('fs')
// 创建 Promise容器
// 1. 给别人一个承诺 
//      Promise 容器一旦创建,就开始执行里面的代码

var p1 = new Promise(function(resolve,reject){
    fs.readFile('./data/a.txt', 'utf8', function(err,data){
        if(err){
            // 失败了,承诺容器中的任务失败了
            // console.log(err)
            // 把容器的Pending状态变为Rejected
            // 调用reject就相当于调用了then的第二个回调函数
            reject(err)
        }
        else {
            // 承诺容器中的任务成功了
            // console.log(data)
            // 把容器的Pending状态改为成功 Resolved
            // 也就是说这里调用的resolve方法实际上就是then方法传递的那个function resolve(data)
        }
    });
})
var p2 = new Promise(function(resolve,reject){
    fs.readFile('./data/b.txt', 'utf8', function(err,data){
        if(err){
            reject(err)
        }
        else{
            resolve(data)
        }
    });
})
// p1 就是那个承诺
// 当 p1 成功了,然后then做指定的操作
// then方法接收的function就是容器中的resolve函数
p1.then(function(data){
    console.log(data) //这是p1返回的数据
    // 当p1读取成功时候
    // 当前函数中return的结果就可以在后面的then中的function接收到
    // 当你return 123 后面就接收到123,return什么后面就接收到的什么
    // 真正有用的是:我们可以return一个promise对象
    // 当return一个Promise对象的时候,后续的then中的方法的第一个参数会作为p2的返回值
    return p2
},function(err){
    console.log('读取文件失败了'+err)
})
.then(function(data){
    console.log(data) // 这个方法就是作为p2的resolve
})
  • 封装Promise版本的ReadFile
var fs = require('fs')

function pReadFile(filePath){
    return new Promise(function(resolve,reject){
        fs.readFile(filePath, 'utf8', function(err,data){
            if(err){
                reject(err)
            }else{
                resolve(data)
            }
        });
    }) 
}

pReadFile('./data/a.txt')
.then(function(data){
    console.log(data)
    return pReadFile('./data/b.txt')
})
.then(function(data){
    console.log(data)
    return pReadFile('./data/c.txt')
})
.then(function(data){
    console.log(data)
})
  • Promise和Callback方式对比

  • callback

get('http://127.0.0.1:3000/users/4',function(userData){
    get('http://127.0.0.1:3000/jobjs',function(jobsData){
        var htmlStr = template('tpl', {
            user: JSON.parse(userData),
            jobs: JSON.parse(jobsData)
        })
        console.log(htmlStr)
        document.querySelector('#user_form').innerHTML = htmlStr
    })
}) 
  • promise
var data = {}
$.get('http://127.0.0.1:3000/users/4')
.then(function(user){
    data.user = user
    return $.get('http://127.0.0.1:3000/jobjs')
})
.then(function(jobs){
    data.jobs = jobs    
    var htmlStr = template('tpl', data)
    document.querySelector('#user_form').innerHTML = htmlStr
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值