NodeJS七天课程学习笔记_第6天

课程内容概要:

1.  Node 中如何操作Mysql数据库 (包括如何使用连接池pool)

2. 将上一个使用MongoDB的CRUB项目改写成使用Mysql

3. 针对回调地狱callback hell 而生的 Promise语法

4. 封装promise版本的自定义ajax的get方法

5. 演示一下promise的使用场景

6. 将前面的node_36_index.js这个mongoose的CRUD案例中的写法改成promise+then的写法

在npmjs.com中搜索mysql,进入使用介绍页面:https://www.npmjs.com/package/mysql

安装mysql:

npm install mysql --save

然后启动本机的Mysql,看一下db2库下面有什么表

根据文档写出node操作mysql的最简单的demo

node_37.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 1.导入框架
var mysql = require('mysql')
// 2.创建连接
var connection = mysql.createConnection({host: 'localhost',user: 'root',password: '520',database: 'db2'
})
// 3.连接数据库
connection.connect();
// 4.查询数据库
var sql = 'select 6+7 as girlAge'
connection.query(sql,function (error,results,fields) {if(error){return NSLog(error)}NSLog('girl is : ' + results[0].girlAge + '岁')
})
// 5.关闭数据库
connection.end()

效果如下:

下面尝试着把user表里的第一条记录查出来:

node_37_query1.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 1.导入框架
var mysql = require('mysql')
// 2.创建连接
var connection = mysql.createConnection({host: 'localhost',user: 'root',password: '520',database: 'db2'
})
// 3.连接数据库
connection.connect();
// 4.查询数据库
var sql = 'select name from user'
connection.query(sql,function (error,results,fields) {if(error){return NSLog(error)}NSLog('girl is : ' + results[0].name)
})
// 5.关闭数据库
connection.end()

效果如下:

通过软件查看本机数据库中的表和记录,这里使用Navicat Premium

打开Navicat Premium12.0.20之后,新建一个连接,如图所示:

然后就可以,连接本机mysql数据库,查看db2数据库里的user表了:

手动新建一个girls的表: (输入完字段名和类型后,Ctrl + S保存,输入表名)

补充一下: 为了安全起见, mysql中没有直接修改 数据库的名字的命令

现在通过node_37_add.js我们来插入一条记录到数据库,代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 1.导入框架
var mysql = require('mysql')
// 2.创建连接
var connection = mysql.createConnection({host: 'localhost',user: 'root',password: '520',database: 'db2'
})
// 3.连接数据库
connection.connect();
// 4.查询数据库
// 如果不指定字段名,则每一个都要填写值(主键可以用null代替)
var sql = 'insert into girls values(null,"面码",15,"未闻花名","2010-06-07")'
connection.query(sql,function (error,results,fields) {if(error){return NSLog(error)}NSLog('插入成功')
})
// 5.关闭数据库
connection.end()

效果如下:

多插入几个,再查询一下:

接下来根着文档写根据_id查询 node_37_findOneById.js代码如下:

(因为后面用Mysql重写CRUD项目中,根据_id进行查询出来后,进入修改页面)

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 1.导入框架
var mysql = require('mysql')
// 2.创建连接
var connection = mysql.createConnection({host: 'localhost',user: 'root',password: '520',database: 'db2'
})
// 3.连接数据库
connection.connect();
// 4.查询数据库
var sql = 'select girlName,girlAge,girlDescription,pubTime from girls where _id = ?'
var queryObj = {'sql': sql,timeout: 6000,values: ['2']}
connection.query(queryObj,function (error,results,fields) {if(error){return NSLog(error)}var girlObj = results[0]NSLog('根据_id = 2 查询成功: \n' + girlObj.girlName + ',' + girlObj.girlAge + ',' + girlObj.girlDescription + ',' + girlObj.pubTime)
})
// 5.关闭数据库
connection.end()

效果如下:

根据_id,删除一条记录node_37_deleteOneById.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 1.导入框架
var mysql = require('mysql')
// 2.创建连接
var connection = mysql.createConnection({host: 'localhost',user: 'root',password: '520',database: 'db2'
})
// 3.连接数据库
connection.connect();
// 4.查询数据库
var sql = 'delete from girls where _id = ?'
var queryObj = {'sql': sql,timeout: 6000,values: ['5']}
connection.query(queryObj,function (error,results,fields) {if(error){return NSLog(error)}NSLog('删除成功')
})
// 5.关闭数据库
connection.end()

效果如下:

查询所有的记录node_37_findAll.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 1.导入框架
var mysql = require('mysql')
// 2.创建连接
var connection = mysql.createConnection({host: 'localhost',user: 'root',password: '520',database: 'db2'
})
// 3.连接数据库
connection.connect();
// 4.查询数据库
var sql = 'select _id,girlName,girlAge,girlDescription,pubTime from girls'
connection.query(sql,function (error,results,fields) {if(error){return NSLog(error)}// 遍历,打印NSLog("查询成功",false)for(var i = 0;i < results.length; i++){var girlObj = results[i]NSLog(girlObj._id + ', ' + girlObj.girlName + ', ' + girlObj.girlAge + '岁, 「' + girlObj.girlDescription + '」, ' + girlObj.pubTime,false)}})
// 5.关闭数据库
connection.end()

效果如下:

更新一条记录node_37_update.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 1.导入框架
var mysql = require('mysql')
// 2.创建连接
var connection = mysql.createConnection({host: 'localhost',user: 'root',password: '520',database: 'db2'
})
// 3.连接数据库
connection.connect();
// 4.查询数据库
var sql = 'update girls set girlName = ?,girlAge = ?,girlDescription = ? where _id = ?'
var queryObj = {'sql': sql,timeout: 6000,values: ['面码',13,'未闻花名','1']}
connection.query(queryObj,function (error,results,fields) {if(error){return NSLog(error)}NSLog('更新成功')
})
// 5.关闭数据库
connection.end()

效果如下:

下面的node_37_poolFindAll.js 将演示一下

如何在Node中使用Mysql的 连接池 Pool Connection :

(因为每次查询都要连接然后断开的话 会非常消耗CPU资源)

(如果每一个用户连接后,又不断开,那么会不断地消耗内存资源)

官方示例代码如下:

npmjs.com/package/mysql#pooling-connections

node_37_poolFindAll.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 1.导入框架
var mysql = require('mysql')
// 2.创建连接
var pool = mysql.createPool({connectionLimit: 10,host: 'localhost',user: 'root',password: '123456',database: 'db2'
})
// 3.直接查询数据库
var sql = 'select _id,girlName,girlAge,girlDescription,pubTime from girls'
pool.query(sql,function (error,results,fields) {if(error){return NSLog(error)}// 遍历,打印NSLog("查询成功",false)for(var i = 0;i < results.length; i++){var girlObj = results[i]NSLog(girlObj._id + ', ' + girlObj.girlName + ', ' + girlObj.girlAge + '岁, 「' + girlObj.girlDescription + '」, ' + girlObj.pubTime,false)}console.log("\nCopyright © 2018 Powered by beyond")
})
// 无需关闭,查询完毕会自动进行连接池 pool

效果如下:

下面把node_36_index.js这个使用MongoDB的CRUD项目,转换成使用Mysql的node_38_index.js项目

项目目录如下:

默认的views目录下的index目录下的3个html模板文件如下:

效果如下:

app入口文件node_38_index.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 导入框架
var express = require('express')
// 创建服务器对象
var appServer = express()
// 监听端口,并启动服务
appServer.listen(5267,function (error) {if (error) {return NSLog('启动失败: ' + error)}NSLog('服务启动成功')
})
// -----------------------------------// 静态资源请求时的 staticFileUrlPrefix
var staticFileUrlPrefix = '/public/'
// var staticFileUrlPrefix = '/public'// 访问也只能使用 localhost:5267/public/img/beyond.jpg
// 磁盘上的静态资源目录
var staticFilePath = './public/'
// var staticFilePath = 'public' var callbackFunction = express.static(staticFilePath)
appServer.use(staticFileUrlPrefix,callbackFunction)// -----------------------------------// 指明:对于 所有后缀为html 的模板文件 使用模板引擎
var templateFileSuffix = 'html'
appServer.engine(templateFileSuffix,require('express-art-template'))
// 下面这一句参数配置,可有可无
appServer.set('view options',{debug: process.env.NODE_ENV !== 'production'
})
// 注意:如果不想把模板文件放在默认的views目录下,则可以通过下面代码更改设置
// appServer.set('views','其他目录')// -----------------------------------
// 使用middleware中间件body-parser进行post请求体中数据解析
var bodyParser = require('body-parser')
// 设置解析 application/x-www-form-urlencoded
appServer.use(bodyParser.urlencoded({extended: false}))
// 设置解析 application/json
appServer.use(bodyParser.json())
// -----------------------------------
// 自定义路由设计的目的是:
// 1.让主入口程序的职责更加单一,代码更加简洁
//     1.1 创建服务
//     1.2 做一些服务相关的配置,比如:
//           1.2.1 静态资源配置
//           1.2.2 模板引擎配置
//           1.2.3 body-parse 解析表单
//           1.2.4 挂载自定义路由
//           1.2.5 监听端口,启动服务
// 使用自定义的路由模块 必须使用./
// 注意: 配置模板引擎和body-parser, 一定要在挂载路由之前
var beyondRouter = require('./node_38_router')
appServer.use(beyondRouter)

路由模块代码node_38_router.js代码如下:

function NSLog(loli) {console.log(loli);return 'Copyright © 2018 Powered by beyond';};
/*自定义路由模块的职责是:专门处理所有的路由根据不同的请求方式和路径,采取相应的处理方法
*/
// express 专门提供了路由的处理方法
var express = require('express')
// 1.使用express专门提供的路由器处理路由
var router = express.Router()// ----------------引入dao模块-------------------
// 先对dao初始化
var poolDao = require('./node_38_dao')
// 时间格式化
var BeyondDateFormatFunction = require('./BeyondDateFormat')// ----------------首页-------------------
router.get('/',function (request,response) {// 至于请求参数可以这样:// var queryObj = request.query// ----------------查找所有------------------var sql = 'select _id,girlName,girlAge,girlDescription,pubTime from girls'poolDao.query(sql,function (error,results,fields) {if(error){return response.send(error)}// 使用模板引擎渲染// 注意: 模板文件默认是放在views目录下// 为此,我们在views目录下  分别为不同的业务模块创建了不同的文件夹// 如 login登录 admin后台管理 index前台首页 article文章 comment评论response.render('index/node_38_index.html',{girlArr:results})})// 无需关闭,查询完毕会自动进行连接池 pool})// ----------------添加的表单页面-------------------
router.get('/add',function (request,response) {response.render('index/node_38_add.html')
})// ----------------增加一条记录-------------------
router.post('/insert',function (request,response) {// 1.body-parser得到objvar girlObj = request.body// 1.调用girlDao写到文件数据库girlObj.pubTime = BeyondDateFormatFunction(new Date(),'yyyy-MM-dd')// 2.保存到数据库// 如果不指定字段名,则每一个都要填写值(主键可以用null代替)var sql = 'insert into girls values(null,?,?,?,?)'var queryObj = {'sql': sql,timeout: 6000,values: [girlObj.girlName,girlObj.girlAge,girlObj.girlDescription,girlObj.pubTime]}poolDao.query(queryObj,function (error,results,fields) {if(error){// 有错误return response.status(500).send(error)}// 没有错误,跳转到首页  response.redirect('/')})
})// ----------------修改页面-------------------
router.get('/edit',function (request,response) {var sql = 'select _id,girlName,girlAge,girlDescription,pubTime from girls where _id = ?'var queryObj = {'sql': sql,timeout: 6000,values: [request.query._id]}poolDao.query(queryObj,function (error,results,fields) {if(error){// 如果出错return response.status(500),send(error)}// 如果查询成功response.render('index/node_38_edit.html',{'girl': results[0]})})
})// ----------------更新数据库-------------------
router.post('/update',function (request,response) {// 1.请求体 id号 (前后多了两个引号,要手动去掉)var girlID = request.body._idvar girlName = request.body.girlNamevar girlAge = request.body.girlAgevar girlDescription = request.body.girlDescription// 2.更新var sql = 'update girls set girlName = ?,girlAge = ?,girlDescription = ? where _id = ?'var queryObj = {'sql': sql,timeout: 6000,values: [girlName,girlAge,girlDescription,girlID]}// 使用连接池更新记录                  poolDao.query(queryObj,function (error,results,fields) {if(error){// 如果失败return response.status(500).send(error)}// 如果成功response.redirect('/')})
})// ----------------删除一条记录-------------------
router.get('/delete',function (request,response) {// 1.获取query对象中的_idvar girlID = request.query._id// 2.调用dao从数据库中删除一个对象var sql = 'delete from girls where _id = ?'var queryObj = {'sql': sql,timeout: 6000,values: [girlID]}// 使用连接池                 poolDao.query(queryObj,function (error,results,fields) {if(error){// 如果错误return response.status(500).send(error)}// 如果没有错误,跳转到首页return response.redirect('/')})
})// 3.在模块文件最后,导出router
module.exports = router

Dao数据库操作文件node_38_dao.js代码如下:

function NSLog(loli) {console.log(loli);return 'Copyright © 2018 Powered by beyond';};  // 1.导入框架
var mysql = require('mysql')
// 2.创建连接
var pool = mysql.createPool({connectionLimit: 10,host: 'localhost',user: 'root',password: '123456',database: 'db2'
})// 3.无需关闭,查询完毕会自动进行连接池 pool// 4.导出连接池
module.exports = pool

三个html文件,代码与前一篇文章node_36_index(add和edit).html几乎一模一样,这儿就不重复显示了

回调地狱callback hell

先上一张经典的图:

演示读取失败时的node_39.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 回调地狱的解决方案演示 Promisevar fs = require('fs')
// 在ECMAScript6中,新增了一个API Promise
// Promise是一个构造函数,目的就是避免回调地狱 callback hell
// 通过new + 构造函数 创建一个Promise
// 构造函数的参数 是一个匿名函数(block代码块)
// Promise一旦创建,就会立即执行参数(即匿名函数block)里面的代码
NSLog('0_before_promise',false)
var promise_1 = new Promise(function () {// Promise本身是同步顺序执行的,但是它里面的异步操作是异步执行的NSLog('1_in_promise',false)fs.readFile('node_39_1.txt','utf8',function (error,data) {NSLog('3_in_promise_block',false)if (error) {// 如果失败,则承诺容器中的异步任务失败了NSLog('读取失败')}else{// 如果成功,则承诺容器中的异步任务成功了NSLog('读取成功: ' + data)}})
})
NSLog('2_after_promise',false)

效果如下:

读取成功时的效果如下:

注意: Promise容器中往往通过构造函数时的参数,传入一个匿名函数(block代码块), 这个block代码块会被立刻执行,
并且,这个block代码块中,往往封装的都是一些异步操作任务

Promise在初始状态时,只是Pending状态
一旦block代码块中的异步操作完成之时,Promise的状态就会发生改变.

当block代码块中的异步操作成功时,Promise状态变成Resolved
当block代码块中的异步操作失败时,Promise状态变成Rejected

示例图如下:

接下来要进入重头戏了,

下面给promise构造函数中的匿名函数(block代码块)写上成功时回调的参数1和失败时回调的参数2

并在异步任务完成时,回调对应的函数

上面的成功时回调的参数1和失败时回调的参数2 对应于 then方法的 参数1 和参数2

下面演示一下promise对象的then方法,以及then方法中的两个参数

node_40.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 回调地狱的解决方案演示 Promise
var fs = require('fs')
// 在ECMAScript6中,新增了一个API Promise
// Promise是一个构造函数,目的就是避免回调地狱 callback hell
// 通过new + 构造函数 创建一个Promise
// 构造函数的参数 是一个匿名函数(block代码块)
// Promise一旦创建,就会立即执行参数(即匿名函数block)里面的代码
// 匿名函数block有两个参数是用于回调的,它们分别是resolveCallBack和rejectCallback
// 对应于then方法的参数1和参数2
NSLog('0_before_promise',false)
var promise_1 = new Promise(function (resolveCallback,rejectCallback) {// Promise本身是同步顺序执行的,但是它里面的异步操作是异步执行的NSLog('1_in_promise',false)fs.readFile('node_39_1.txt','utf8',function (error,successData) {NSLog('5_in_promise_block',false)if (error === null) {// 如果成功,则承诺容器中的异步任务成功了// 成功回调函数(即then方法的参数1)resolveCallback(successData)}else{// 如果失败,则承诺容器中的异步任务失败了// NSLog('读取失败' + error)// 失败回调函数(即then方法的参数2)rejectCallback(error)}})
})NSLog('2_after_promise',false)
NSLog('3_before_then',false)promise_1.then(function (successData) {NSLog('6.读取成功: ' + successData)
},function (error) {NSLog('6.读取失败: ' + error)
})
NSLog('4_after_then',false)

效果如下:

示意图如下:

关于 在then的参数(即匿名函数)中返回值 的说明
这个返回值类型 只有两种情况
第1种情况: 返回一个promise对象 (最常见)
  那么下一个then中,参数1就是promise对象的resolveCallback
  参数2就是promise对象的rejectCallback
第2种情况: 返回一个非Promise的对象 (极少用到)
  比如返回一个String字符串 "未闻花名"
  那么,在下一个then中就只有一个匿名函数callback作为参数
  那个匿名函数callback中的参数 就是这儿的返回值 即String的值  "未闻花名"

下面再进一步演示一下,如果在then中返回一个字符串会怎么样

node_42.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 回调地狱的解决方案演示 Promisevar fs = require('fs')
// 在ECMAScript6中,新增了一个API Promise
// Promise是一个构造函数,目的就是避免回调地狱 callback hell
// 通过new + 构造函数 创建一个Promise
// 构造函数的参数 是一个匿名函数(block代码块)
// Promise一旦创建,就会立即执行参数(即匿名函数block)里面的代码
// 匿名函数block有两个参数是用于回调的,它们分别是resolveCallBack和rejectCallback
// 对应于then方法的参数1和参数2
NSLog('0_before_promise_1',false)
var promise_1 = new Promise(function (resolveCallback,rejectCallback) {// Promise本身是同步顺序执行的,但是它里面的异步操作是异步执行的NSLog('1_in_promise_1',false)fs.readFile('node_40_1.txt','utf8',function (error,successData) {if (error === null) {// 如果成功,则承诺容器中的异步任务成功了// 成功回调函数(即then方法的参数1)resolveCallback(successData)}else{// 如果失败,则承诺容器中的异步任务失败了// NSLog('读取失败' + error)// 失败回调函数(即then方法的参数2)rejectCallback(error)}})
})NSLog('2_after_promise',false)
NSLog('3_before_then',false)promise_1.then(function (successData) {NSLog('5.读取txt成功: \n' + successData,false)/*关于这个返回值 要说明一下这个返回值类型 只有两种情况第1种情况: 返回一个promise对象那么下一个then中,参数1就是promise对象的resolveCallback参数2就是promise对象的rejectCallback第2种情况: 返回一个非Promise的对象 (极少用到)  比如返回一个String字符串  "那朵花"那么,在下一个then中就只有一个匿名函数callback作为参数那个匿名函数callback中的参数 就是这儿的返回值 即String的值  "那朵花" */ return "未闻花名"
},function (error) {NSLog('5.读取txt失败: \n' + error,false)/*关于这个返回值 要说明一下这个返回值类型 只有两种情况第1种情况: 返回一个promise对象那么下一个then中,参数1就是promise对象的resolveCallback参数2就是promise对象的rejectCallback第2种情况: 返回一个非Promise的对象 (极少用到) 比如返回一个String字符串  "那朵花"那么,在下一个then中就只有一个匿名函数callback作为参数那个匿名函数callback中的参数 就是这儿的返回值 即String的值  "那朵花" */ return "anohana"
}).then(function (previousThenReturnData) {NSLog('6.这个是上一个then中的返回值: \n   ' + previousThenReturnData)
})
NSLog('4_after_then',false)

成功时效果如下:

失败时效果如下:

下面最核心最精华的部分了, 我们使用Promise的目的是避免回调地狱的同时,又要保证N个异步任务的结果,按顺序输出

比如下面的promise_1和promise_2和promise_3分别读取a,b,c三个txt方法,并按顺序输出其内容

在这儿我们就需要在promise_1的then方法中 输出了a.txt内容之后,return promise_2,

这样我们就可以继续调用promise_2的then方法中 输出b.txt的内容,

输出了b.txt内容之后同样的,我们返回promise_3对象,

这样我们就可以继续调用promise_3的then方法中 输出c.txt的内容

示例代码node_41.js如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 回调地狱的解决方案演示 Promisevar fs = require('fs')
// 在ECMAScript6中,新增了一个API Promise
// Promise是一个构造函数,目的就是避免回调地狱 callback hell
// 通过new + 构造函数 创建一个Promise
// 构造函数的参数 是一个匿名函数(block代码块)
// Promise一旦创建,就会立即执行参数(即匿名函数block)里面的代码
// 匿名函数block有两个参数是用于回调的,它们分别是resolveCallBack和rejectCallback
// 对应于then方法的参数1和参数2
NSLog('0_before_promise_1',false)
var promise_1 = new Promise(function (resolveCallback,rejectCallback) {// Promise本身是同步顺序执行的,但是它里面的异步操作是异步执行的NSLog('1_in_promise_1',false)fs.readFile('node_40_1.txt','utf8',function (error,successData) {if (error === null) {// 如果成功,则承诺容器中的异步任务成功了// 成功回调函数(即then方法的参数1)resolveCallback(successData)}else{// 如果失败,则承诺容器中的异步任务失败了// NSLog('读取失败' + error)// 失败回调函数(即then方法的参数2)rejectCallback(error)}})
})var promise_2 = new Promise(function (resolveCallback,rejectCallback) {// Promise本身是同步顺序执行的,但是它里面的异步操作是异步执行的NSLog('2_in_promise_2',false)fs.readFile('node_40_2.txt','utf8',function (error,successData) {if (error === null) {// 如果成功,则承诺容器中的异步任务成功了// 成功回调函数(即then方法的参数1)resolveCallback(successData)}else{// 如果失败,则承诺容器中的异步任务失败了// NSLog('读取失败' + error)// 失败回调函数(即then方法的参数2)rejectCallback(error)}})
})var promise_3 = new Promise(function (resolveCallback,rejectCallback) {// Promise本身是同步顺序执行的,但是它里面的异步操作是异步执行的NSLog('3_in_promise_3',false)fs.readFile('node_40_3.txt','utf8',function (error,successData) {if (error === null) {// 如果成功,则承诺容器中的异步任务成功了// 成功回调函数(即then方法的参数1)resolveCallback(successData)}else{// 如果失败,则承诺容器中的异步任务失败了// NSLog('读取失败' + error)// 失败回调函数(即then方法的参数2)rejectCallback(error)}})
})NSLog('4_after_promise_3',false)
NSLog('5_before_then',false)promise_1.then(function (successData) {NSLog('10.读取1.txt成功: \n' + successData,false)return promise_2
},function (error) {NSLog('10.读取1.txt失败: \n' + error)return promise_2
}).then(function (successData) {NSLog('11.读取2.txt成功: \n' + successData,false)return promise_3
},function (error) {NSLog('11.读取2.txt失败: \n' + error)return promise_3
}).then(function (successData) {NSLog('12.读取3.txt成功: \n' + successData)},function (error) {NSLog('12.读取3.txt失败: \n' + error)
})
NSLog('6_after_then',false)

效果如下:

注意:  之所有 没有 7 8 9 ,是因为 三个block代码块中的异步操作 谁先完成  这个顺序是不确定的

示意图如下:

下面演示了自定义一个函数,参数是 文件路径,返回值是一个Promise

node_43.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 回调地狱的解决方案演示 Promise
var fs = require('fs')
// 自己封装一个readFile方法,参数是: filePath
// 返回值是: 一个promise
function beyondReadFile (filePath) {// 在ECMAScript6中,新增了一个API Promise// Promise是一个构造函数,目的就是避免回调地狱 callback hell// 通过new + 构造函数 创建一个Promise// 构造函数的参数 是一个匿名函数(block代码块)// Promise一旦创建,就会立即执行参数(即匿名函数block)里面的代码// 匿名函数block有两个参数是用于回调的,它们分别是resolveCallBack和rejectCallback// 对应于then方法的参数1和参数2var promise_1 = new Promise(function (resolveCallback,rejectCallback) {// Promise本身是同步顺序执行的,但是它里面的异步操作是异步执行的fs.readFile(filePath,'utf8',function (error,successData) {if (error === null) {// 如果成功,则承诺容器中的异步任务成功了// 成功回调函数(即then方法的参数1)resolveCallback(successData)} else{// 如果失败,则承诺容器中的异步任务失败了// NSLog('读取失败' + error)// 失败回调函数(即then方法的参数2)rejectCallback(error)}})})// 返回promise,目的是为了能够链式使用then语法return promise_1
}// 调用一下,因为返回值是promise,所以可直接then
beyondReadFile('node_40_1.txt').then(function (successData) {NSLog('读取1.txt成功:\n   ' + successData)// 见下一个示例},function (error) {NSLog('读取1.txt失败:\n   ' + error)})

效果如下:

下面是Promise的精华部分了,请看演示demo  node_44.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 回调地狱的解决方案演示 Promise
var fs = require('fs')
// 自己封装一个readFile方法,参数是: filePath
// 返回值是: 一个promise
function beyondReadFile (filePath) {// 在ECMAScript6中,新增了一个API Promise// Promise是一个构造函数,目的就是避免回调地狱 callback hell// 通过new + 构造函数 创建一个Promise// 构造函数的参数 是一个匿名函数(block代码块)// Promise一旦创建,就会立即执行参数(即匿名函数block)里面的代码// 匿名函数block有两个参数是用于回调的,它们分别是resolveCallBack和rejectCallback// 对应于then方法的参数1和参数2var promise_1 = new Promise(function (resolveCallback,rejectCallback) {// Promise本身是同步顺序执行的,但是它里面的异步操作是异步执行的fs.readFile(filePath,'utf8',function (error,successData) {if (error === null) {// 如果成功,则承诺容器中的异步任务成功了// 成功回调函数(即then方法的参数1)resolveCallback(successData)} else{// 如果失败,则承诺容器中的异步任务失败了// NSLog('读取失败' + error)// 失败回调函数(即then方法的参数2)rejectCallback(error)}})})// 返回promise,目的是为了能够链式使用then语法return promise_1
}// 调用一下,因为返回值是promise,所以可直接then
beyondReadFile('node_40_1.txt').then(function (successData1) {NSLog('读取1.txt成功:\n   ' + successData1,false)// 下面是Promise最精彩的部分var promise_2 = beyondReadFile('node_40_2.txt')return promise_2/*关于这个返回值 要说明一下这个返回值类型 只有两种情况第1种情况: 返回一个promise对象那么下一个then中,参数1就是promise对象的resolveCallback参数2就是promise对象的rejectCallback第2种情况: 返回一个非Promise的对象 (极少用到)   比如返回一个String字符串  "那朵花"那么,在下一个then中就只有一个匿名函数callback作为参数那个匿名函数callback中的参数 就是这儿的返回值 即String的值  "那朵花" */},function (error1) {NSLog('读取1.txt失败:\n   ' + error1)})// 因为前面返回的是Promsise_2,所以可以接着then.then(function (successData2) {NSLog('读取2.txt成功:\n   ' + successData2)},function (error2) {NSLog('读取2.txt失败:\n   ' + error2)})

效果如下:

依此类推,下面的node_45.js演示的是读取并按顺序输出3个文件,代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  // 回调地狱的解决方案演示 Promise
var fs = require('fs')
// 自己封装一个readFile方法,参数是: filePath
// 返回值是: 一个promise
function beyondReadFile (filePath) {// 在ECMAScript6中,新增了一个API Promise// Promise是一个构造函数,目的就是避免回调地狱 callback hell// 通过new + 构造函数 创建一个Promise// 构造函数的参数 是一个匿名函数(block代码块)// Promise一旦创建,就会立即执行参数(即匿名函数block)里面的代码// 匿名函数block有两个参数是用于回调的,它们分别是resolveCallBack和rejectCallback// 对应于then方法的参数1和参数2var promise_1 = new Promise(function (resolveCallback,rejectCallback) {// Promise本身是同步顺序执行的,但是它里面的异步操作是异步执行的fs.readFile(filePath,'utf8',function (error,successData) {if (error === null) {// 如果成功,则承诺容器中的异步任务成功了// 成功回调函数(即then方法的参数1)resolveCallback(successData)} else{// 如果失败,则承诺容器中的异步任务失败了// NSLog('读取失败' + error)// 失败回调函数(即then方法的参数2)rejectCallback(error)}})})// 返回promise,目的是为了能够链式使用then语法return promise_1
}// 调用一下,因为返回值是promise,所以可直接then
beyondReadFile('node_40_1.txt').then(function (successData1) {NSLog('读取1.txt成功:\n   ' + successData1,false)// 下面是Promise最精彩的部分var promise_2 = beyondReadFile('node_40_2.txt')return promise_2/*关于这个返回值 要说明一下这个返回值类型 只有两种情况第1种情况: 返回一个promise对象那么下一个then中,参数1就是promise对象的resolveCallback参数2就是promise对象的rejectCallback第2种情况: 返回一个非Promise的对象 (极少用到)   比如返回一个String字符串  "那朵花"那么,在下一个then中就只有一个匿名函数callback作为参数那个匿名函数callback中的参数 就是这儿的返回值 即String的值  "那朵花" */},function (error1) {NSLog('读取1.txt失败:\n   ' + error1)})// 因为前面返回的是Promsise_2,所以可以接着then.then(function (successData2) {NSLog('读取2.txt成功:\n   ' + successData2,false)// 下面是Promise最精彩的部分var promise_3 = beyondReadFile('node_40_3.txt')return promise_3/*关于这个返回值 要说明一下这个返回值类型 只有两种情况第1种情况: 返回一个promise对象那么下一个then中,参数1就是promise对象的resolveCallback参数2就是promise对象的rejectCallback第2种情况: 返回一个非Promise的对象 (极少用到)   比如返回一个String字符串  "那朵花"那么,在下一个then中就只有一个匿名函数callback作为参数那个匿名函数callback中的参数 就是这儿的返回值 即String的值  "那朵花" */},function (error2) {NSLog('读取2.txt失败:\n   ' + error2)})// 因为前面返回的是Promsise_2,所以可以接着then.then(function (successData3) {NSLog('读取3.txt成功:\n   ' + successData3)},function (error3) {NSLog('读取3.txt失败:\n   ' + error3)})

效果如下:

整个效果如下:

解释说明如下:

下面演示一个Promise使用场景的示例demo,

在这个demo中,教程里面使用了json-server来提供api接口(因此,我们先来安装和使用json-server)

下面,我们先根据npmjs.com上面的json-server的官方文档,安装和使用json-server

npmjs.com/package/json-server

第1步, 安装命令如下:

sudo npm install --global json-server

效果如下:

第2步, 创建597_db.json,内容如下:

注意: 主键属性名必须叫id

{"girls" : [{"id" : 1,"girlName" : "面码","girlAge" : 13,"animeId" : 1},{"id" : 2,"girlName" : "mathilda","girlAge" : 12,"animeId" : 2},{"id" : 3,"girlName" : "逢坂大河","girlAge" : 16,"animeId" : 3},{"id" : 4,"girlName" : "平泽唯","girlAge" : 14,"animeId" : 4}],"animes" : [{"id" : 1, "animeName" : "未闻花名"},{"id" : 2,"animeName" : "这个杀手不太冷"},{"id" : 3,"animeName" : "龙与虎"},{"id" : 4,"animeName" : "轻音少女"}]
}

第3步, cd json所在目录,然后执行下面命令

json-server --watch 597_girls.json

效果如下:

第4步, 在地址栏输入 localhost:3000/girls   回车,请求接口时,返回的json结果如下:

输入localhost:3000/girls/1 回车,请求接口时,返回的json效果如下:

输入localhost:3000/animes 回车,请求接口时,返回的json效果如下:

教程中接下来又使用了一个命令

这个hs -c-l -o命令又是一个什么东东???

老规矩,先来安装一下 http-server

第1步, 使用以下命令

sudo npm install --global http-server

效果如下:

第2步, 启动http-server,输入

hs -c-l -o

效果如下:

官方说明如下: (意思是如果根目录下面没有public目录,就显示根目录文件列表)

http-server [path] [options]
[path] defaults to ./public if the folder exists, and ./ otherwise.Now you can visit http://localhost:8080 to view your server

接下来安装模板引擎art-template

命令如下:

npm install art-template

效果如下:

接下来在597.html中使用模板引擎template-web.js

注意: json服务器的接口是 localhost:3000/girls/1

而http-server提供的服务器是 localhost:8080/597.html

我们在597.html中,使用596.html中自己封装的beyondGet方法,发送一个ajax请求 json服务器上的数据,

并且将返回的json字符串解析成对象,通过模板引擎,填充到form表单列表中

现在我们的597.html到底是要实现什么样的场景呢?

那就是: 发两次异步请求

第1次异步请求回girl的信息,其中girl对象中有一个属性animeId,记录她出演的动漫id

第2次异步请求回动漫列表

等两次请求相继完成后,我们再进行页面的渲染,并且在渲染的时候,会判断

如果girl对象的animeId属性  跟下拉的动漫列表 框中的id一致时,我们就让这个option默认为选中状态

下面是不用Promise的写法:

597.html代码如下:

<!DOCTPYE html>
<html lang="zh">
<head>  <link rel="icon" href="beyond2.jpg" type="image/x-icon"/><meta charset="UTF-8"><meta name="author" content="beyond"><meta http-equiv="refresh" content="520"><meta name="description" content="未闻花名-免费零基础教程-beyond"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0" /><meta name="keywords" content="HTML,CSS,JAVASCRIPT,JQUERY,XML,JSON,C,C++,C#,OC,PHP,JAVA,JSP,PYTHON,RUBY,PERL,LUA,SQL,LINUX,SHELL,汇编,日语,英语,泰语,韩语,俄语,粤语,阿语,魔方,乐理,动漫,PR,PS,AI,AE"><title>beyond心中の动漫神作</title><link rel="stylesheet" type="text/css" href="beyondbasestylewhite5.css"><script type="text/javascript" src="nslog.js"></script><!--[if lt IE 9]><script src="//apps.bdimg.com/libs/html5shiv/3.7/html5shiv.min.js"></script><script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.js"></script><![endif]--><style type="text/css">body{font-size: 100%; /*声明margin和padding是个好习惯*/  margin: 0;  padding: 0; background-image: url("sakura4.png");  background-repeat: no-repeat;  background-position: center center;  }</style><!-- 绿色按钮的css效果 --><link rel="stylesheet" type="text/css" href="beyondbuttongreen.css"><!-- 引入 jquery 2.1.4 --><!--[if gte IE 9]><!--> <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.js"></script><!--<![endif]--></head>  <body>  <h1 style="color:white;text-shadow:2px 2px 4px #000;letter-spacing:5px;" class="sgcontentcolor sgcenter">  未闻花名</h1><!-- 渲染结果显示区域 --><form action="" id="id_form_renderResult" style="text-align:center;" ></form><!-- 第1步,导入template-web.js -->
<script type="text/javascript" src="node_modules/art-template/lib/template-web.js"></script><!-- 第2步,定义模板引擎 -->  <!-- type只要 不是javascript即可,随便起,无意义   id 在第3步填充数据时用到  -->
<script type="text/beyondtemplate" id="art_template">  <div ><label for="">芳名</label>    <input type="text" value="{{ girl.girlName }}"/></div><div ><label for="">年龄</label>    <input type="text" value="{{ girl.girlAge }}"/></div><div><label for="">主演动漫</label><select>{{ each animes }}{{ if girl.animeId === $value.id }}<option value="{{ $value.id }}" selected> {{ $value.animeName }} </option>{{ else }}<option value="{{ $value.id }}"> {{ $value.animeName }} </option>{{ /if }}{{ /each }}</select></div>
</script>        <button id="id_btn" class="class_btn class_btn_green" type="button" style="display:block;margin:auto;margin-top:10px;">点我试试</button><script type="text/javascript">// 自己封装一个get请求  function beyondGet (url,callback) {  // 自己实现一个ajax请求  // 1. 创建xhr  var xmlHttpRequest = new XMLHttpRequest()  // 2. 请求url资源  xmlHttpRequest.onload = function () {  // 5. 核心代码,回调结果  callback(xmlHttpRequest.responseText)}  // 3.连接资源  xmlHttpRequest.open("get",url,true)  // 4.发送请求  xmlHttpRequest.send()  }  $(document).ready(function () {  $(".class_btn_green").click(function () {  // 使用自己封装的ajax请求  // 第1个接口, 获取girl的数据beyondGet("http://127.0.0.1:3000/girls/2",function (responseGirl) {  var girlObj = JSON.parse(responseGirl)// 第2个接口,获取所有的动漫列表接口beyondGet('http://127.0.0.1:3000/animes',function (responseAnimes) {var animeArr = JSON.parse(responseAnimes)// <!-- 第3步,给模板引擎绑定数据 -->  // 注意: 函数名,必须是template  // 参数1: 模板的id  // 参数2: 要填充的数据封装成的 对象  var resultHTML = template('art_template',{girl: girlObj,animes: animeArr})// 这是干嘛:将渲染后的字符串,显示到界面上document.querySelector('#id_form_renderResult').innerHTML = resultHTMLNSLog('resultHTML: \n' + resultHTML)})})  })  })</script><p class="sgcenter"><b>注意:</b>模拟Promise使用场景<br/>json-server提供API服务(3000端口)<br/>http-server提供Web服务(8080端口)<br/>封装了XMLHttpRequest.onload方法<br/>art-template的template-web.js渲染</p><footer id="copyright"><p style="font-size:14px;text-align:center;font-style:italic;">  Copyright © <a id="author">2018</a> Powered by <a id="author">beyond</a>  </p>        </footer></body>
</html>  

效果如下:

下面的598.html中使用的是jQuery的get方法(支持Promise),代码如下:

注意$.get(urlPath)只有一个参数时,默认返回的是一个Promise

<!DOCTPYE html>
<html lang="zh">
<head>  <link rel="icon" href="beyond2.jpg" type="image/x-icon"/><meta charset="UTF-8"><meta name="author" content="beyond"><meta http-equiv="refresh" content="520"><meta name="description" content="未闻花名-免费零基础教程-beyond"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0" /><meta name="keywords" content="HTML,CSS,JAVASCRIPT,JQUERY,XML,JSON,C,C++,C#,OC,PHP,JAVA,JSP,PYTHON,RUBY,PERL,LUA,SQL,LINUX,SHELL,汇编,日语,英语,泰语,韩语,俄语,粤语,阿语,魔方,乐理,动漫,PR,PS,AI,AE"><title>beyond心中の动漫神作</title><link rel="stylesheet" type="text/css" href="beyondbasestylewhite5.css"><script type="text/javascript" src="nslog.js"></script><!--[if lt IE 9]><script src="//apps.bdimg.com/libs/html5shiv/3.7/html5shiv.min.js"></script><script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.js"></script><![endif]--><style type="text/css">body{font-size: 100%; /*声明margin和padding是个好习惯*/  margin: 0;  padding: 0; background-image: url("sakura4.png");  background-repeat: no-repeat;  background-position: center center;  }</style><!-- 绿色按钮的css效果 --><link rel="stylesheet" type="text/css" href="beyondbuttongreen.css"><!-- 引入 jquery 2.1.4 --><!--[if gte IE 9]><!--> <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.js"></script><!--<![endif]--></head>  <body>  <h1 style="color:white;text-shadow:2px 2px 4px #000;letter-spacing:5px;" class="sgcontentcolor sgcenter">  未闻花名</h1><!-- 渲染结果显示区域 --><form action="" id="id_form_renderResult" style="text-align:center;" ></form><!-- 第1步,导入template-web.js -->
<script type="text/javascript" src="node_modules/art-template/lib/template-web.js"></script><!-- 第2步,定义模板引擎 -->  <!-- type只要 不是javascript即可,随便起,无意义   id 在第3步填充数据时用到  -->
<script type="text/beyondtemplate" id="art_template">  <div ><label for="">芳名</label>    <input type="text" value="{{ girl.girlName }}"/></div><div ><label for="">年龄</label>    <input type="text" value="{{ girl.girlAge }}"/></div><div><label for="">主演动漫</label><select>{{ each animes }}{{ if girl.animeId === $value.id }}<option value="{{ $value.id }}" selected> {{ $value.animeName }} </option>{{ else }}<option value="{{ $value.id }}"> {{ $value.animeName }} </option>{{ /if }}{{ /each }}</select></div>
</script>        <button id="id_btn" class="class_btn class_btn_green" type="button" style="display:block;margin:auto;margin-top:10px;">点我试试</button><script type="text/javascript">var girlObj = null $(document).ready(function () {  $(".class_btn_green").click(function () {  // 使用自己封装的ajax请求  // 第1个接口, 获取girl的数据// get方法只有一个参数时,返回的就是一个Promise$.get("http://127.0.0.1:3000/girls/2").then(function (responseGirlObj) {  // 因为第2个接口中拿不到,所以使用全局变量girlObj = responseGirlObj// 返回一个Promise// 第2个接口,获取所有的动漫列表接口$.get('http://127.0.0.1:3000/animes')}).then(function (responseAnimes) {var animeArr = responseAnimes// <!-- 第3步,给模板引擎绑定数据 -->  // 注意: 函数名,必须是template  // 参数1: 模板的id  // 参数2: 要填充的数据封装成的 对象  var resultHTML = template('art_template',{girl: girlObj,animes: animeArr})// 这是干嘛:将渲染后的字符串,显示到界面上document.querySelector('#id_form_renderResult').innerHTML = resultHTMLNSLog('resultHTML: \n' + resultHTML)})})  })</script><p class="sgcenter"><b>注意:</b>模拟Promise使用场景<br/>json-server提供API服务(3000端口)<br/>http-server提供Web服务(8080端口)<br/>jQuery的get方法 默认 支持Promise<br/>art-template的template-web.js渲染</p><footer id="copyright"><p style="font-size:14px;text-align:center;font-style:italic;">  Copyright © <a id="author">2018</a> Powered by <a id="author">beyond</a>  </p>        </footer></body>
</html>  

效果如下:

下面的599.html中使用的是自己封装的Get + Promise方法,代码如下:

<!DOCTPYE html>
<html lang="zh">
<head>  <link rel="icon" href="beyond2.jpg" type="image/x-icon"/><meta charset="UTF-8"><meta name="author" content="beyond"><meta http-equiv="refresh" content="520"><meta name="description" content="未闻花名-免费零基础教程-beyond"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0" /><meta name="keywords" content="HTML,CSS,JAVASCRIPT,JQUERY,XML,JSON,C,C++,C#,OC,PHP,JAVA,JSP,PYTHON,RUBY,PERL,LUA,SQL,LINUX,SHELL,汇编,日语,英语,泰语,韩语,俄语,粤语,阿语,魔方,乐理,动漫,PR,PS,AI,AE"><title>beyond心中の动漫神作</title><link rel="stylesheet" type="text/css" href="beyondbasestylewhite5.css"><script type="text/javascript" src="nslog.js"></script><!--[if lt IE 9]><script src="//apps.bdimg.com/libs/html5shiv/3.7/html5shiv.min.js"></script><script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.js"></script><![endif]--><style type="text/css">body{font-size: 100%; /*声明margin和padding是个好习惯*/  margin: 0;  padding: 0; background-image: url("sakura4.png");  background-repeat: no-repeat;  background-position: center center;  }</style><!-- 绿色按钮的css效果 --><link rel="stylesheet" type="text/css" href="beyondbuttongreen.css"><!-- 引入 jquery 2.1.4 --><!--[if gte IE 9]><!--> <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.js"></script><!--<![endif]--></head>  <body>  <h1 style="color:white;text-shadow:2px 2px 4px #000;letter-spacing:5px;" class="sgcontentcolor sgcenter">  未闻花名</h1><!-- 渲染结果显示区域 --><form action="" id="id_form_renderResult" style="text-align:center;" ></form><!-- 第1步,导入template-web.js -->
<script type="text/javascript" src="node_modules/art-template/lib/template-web.js"></script><!-- 第2步,定义模板引擎 -->  <!-- type只要 不是javascript即可,随便起,无意义   id 在第3步填充数据时用到  -->
<script type="text/beyondtemplate" id="art_template">  <div ><label for="">芳名</label>    <input type="text" value="{{ girl.girlName }}"/></div><div ><label for="">年龄</label>    <input type="text" value="{{ girl.girlAge }}"/></div><div><label for="">主演动漫</label><select>{{ each animes }}{{ if girl.animeId === $value.id }}<option value="{{ $value.id }}" selected> {{ $value.animeName }} </option>{{ else }}<option value="{{ $value.id }}"> {{ $value.animeName }} </option>{{ /if }}{{ /each }}</select></div>
</script>        <button id="id_btn" class="class_btn class_btn_green" type="button" style="display:block;margin:auto;margin-top:10px;">点我试试</button><script type="text/javascript">// 自己封装一个get请求 (返回Promise)function beyondGet (url,callBack) {  var promise = new Promise(function (resolveCallback,rejectCallback) {// 异步请求// 自己实现一个ajax请求  // 1. 创建xhr  var xmlHttpRequest = new XMLHttpRequest()  // 2. 请求url资源  xmlHttpRequest.onload = function () {  // 5. 核心代码,回调结果  // 既可以在参数中传入callBack,使用回调模式,又可以不传而使用.then形式// 当用户不传callBack时,使用.then形式callBack && callBack(xmlHttpRequest.responseText)resolveCallback(JSON.parse(xmlHttpRequest.responseText))}  xmlHttpRequest.onerror = function (error) {// 5.核心代码,回调结果rejectCallback(error)}// 3.连接资源  xmlHttpRequest.open("get",url,true)  // 4.发送请求  xmlHttpRequest.send() })// 核心代码,返回promisereturn promise} var girlObj = null $(document).ready(function () {  $(".class_btn_green").click(function () {  // 使用自己封装的ajax请求  // 第1个接口, 获取girl的数据// 自定义的get方法 返回的就是一个PromisebeyondGet("http://127.0.0.1:3000/girls/2").then(function (responseGirlObj) {// 因为第2个接口中拿不到,所以使用全局变量girlObj = responseGirlObj// 返回一个Promise// 第2个接口,获取所有的动漫列表接口var promise_2 = beyondGet('http://127.0.0.1:3000/animes')return promise_2}).then(function (responseAnimes) {var animeArr = responseAnimes// <!-- 第3步,给模板引擎绑定数据 -->  // 注意: 函数名,必须是template  // 参数1: 模板的id  // 参数2: 要填充的数据封装成的 对象  var resultHTML = template('art_template',{girl: girlObj,animes: animeArr})// 这是干嘛:将渲染后的字符串,显示到界面上document.querySelector('#id_form_renderResult').innerHTML = resultHTMLNSLog('resultHTML: \n' + resultHTML)})})  })</script><p class="sgcenter"><b>注意:</b>模拟Promise使用场景<br/>json-server提供API服务(3000端口)<br/>http-server提供Web服务(8080端口)<br/>自己封装Get方法 (return Promise)<br/>既可以在Get参数中 传入callBack形式<br/>又可不传callBack参数,使用.then形式<br/>art-template的template-web.js渲染</p><footer id="copyright"><p style="font-size:14px;text-align:center;font-style:italic;">  Copyright © <a id="author">2018</a> Powered by <a id="author">beyond</a>  </p>        </footer></body>
</html>  

效果如下:

最后,我们把前面的mongoose案例node_36_router.js这个文件

全部改写成return Promise 加 .then调用形式

(另外的node_36_index.js和node_36_dao.js以及3个html文件 几乎都不用动)

改写后的代码node_47_router.js代码如下:

function NSLog(loli) {console.log(loli);return 'Copyright © 2018 Powered by beyond';};
/*自定义路由模块的职责是:专门处理所有的路由根据不同的请求方式和路径,采取相应的处理方法
*/
// express 专门提供了路由的处理方法
var express = require('express')
// 1.使用express专门提供的路由器处理路由
var router = express.Router()// ----------------引入dao模块-------------------
// 先对dao初始化
var GirlDaoFunction = require('./node_47_dao')
// 时间格式化
var BeyondDateFormatFunction = require('./BeyondDateFormat')// ----------------首页-------------------
router.get('/',function (request,response) {// 至于请求参数可以这样:// var queryObj = request.query// ----------------查找所有------------------// 查找所有,第1个参数不写,就是查找所有GirlDaoFunction.find()// find 方法返回的是:promise// promise的then方法的参数1是 resolveCallback// promise的then方法的参数2是 rejectCallback.then(function (girls) {// then方法的参数1是: resolveCallback// 使用模板引擎渲染// 注意: 模板文件默认是放在views目录下// 为此,我们在views目录下  分别为不同的业务模块创建了不同的文件夹// 如 login登录 admin后台管理 index前台首页 article文章 comment评论response.render('index/node_47_index.html',{girlArr:girls})},function (error) {// then方法的参数2是: rejectCallbackif (error) {return NSLog('查询出错: ' + error)}})})// ----------------添加的表单页面-------------------
router.get('/add',function (request,response) {response.render('index/node_47_add.html')
})// ----------------增加一条记录-------------------
router.post('/insert',function (request,response) {// 1.body-parser得到objvar girlObj = request.body// NSLog(girlObj)// 1.调用girlDao写到文件数据库girlObj.pubTime = BeyondDateFormatFunction(new Date(),'yyyy-MM-dd')var newGirl = new GirlDaoFunction(girlObj)// 2.保存到数据库newGirl.save()// save 方法返回的是:promise// promise的then方法的参数1是 resolveCallback// promise的then方法的参数2是 rejectCallback.then(function () {// then方法的参数1是: resolveCallback// 没有错误,跳转到首页   response.redirect('/')},function(error) {// then方法的参数2是: rejectCallbackif (error) {// 有错误return response.status(500).send(error)}})
})// ----------------修改页面-------------------
router.get('/edit',function (request,response) {// 查询的girlID 不知怎么滴,首尾有引号//  "5ad42675f917fa32e250a58a"// 使用正则,把引号去掉, 如果不使用g的话,仅仅只是去掉第1个引号var pureId = request.query._id.replace(/"/g,"")// NSLog('query: ' + pureId)GirlDaoFunction.findById(pureId)// findById 方法返回的是:promise// promise的then方法的参数1是 resolveCallback// promise的then方法的参数2是 rejectCallback.then(function (girl) {// then方法的参数1是: resolveCallbackresponse.render('index/node_47_edit.html',{'girl': girl})},function (error) {// then方法的参数2是: rejectCallbackif (error) {return response.status(500),send(error)}})
})
// ----------------更新数据库-------------------
router.post('/update',function (request,response) {// 1.请求体 id号 (前后多了两个引号,要手动去掉)var girlID = request.body._idvar girlIDWithoutQuote = girlID.replace(/"/g,'')// 2.重新设置回去request.body._id = girlIDWithoutQuote// 3.根据id查询和更新GirlDaoFunction.findByIdAndUpdate(girlIDWithoutQuote,request.body)// findByIdAndUpdate 方法返回的是:promise// promise的then方法的参数1是 resolveCallback// promise的then方法的参数2是 rejectCallback.then(function () {// then方法的参数1是: resolveCallback// 如果保存成功,回首页response.redirect('/')},function() {// then方法的参数2是: rejectCallbackif(error){// 如果保存出错了return response.status(500).send(error)}})
})// ----------------删除一条记录-------------------
router.get('/delete',function (request,response) {// 1.获取query对象中的_idvar girlID = request.query._idvar girlIDWithoutQuote = girlID.replace(/"/g,'')// 2.调用dao从数据库中删除一个对象GirlDaoFunction.findByIdAndRemove(girlIDWithoutQuote)// findByIdAndRemove 方法返回的是:promise// promise的then方法的参数1是 resolveCallback// promise的then方法的参数2是 rejectCallback.then(function () {// then方法的参数1是: resolveCallback// 如果没有错误,跳转到首页return response.redirect('/')},function(error) {// then方法的参数2是: rejectCallbackif (error) {// 有错误return response.status(500).send(error)}})
})// 3.在模块文件最后,导出router
module.exports = router

效果如下: (跟node_36_router.js效果是一样的)

附上原来的使用callback回调函数作参数的写法的node_36_router.js对比一下

function NSLog(loli) {console.log(loli);return 'Copyright © 2018 Powered by beyond';};
/*自定义路由模块的职责是:专门处理所有的路由根据不同的请求方式和路径,采取相应的处理方法
*/
// express 专门提供了路由的处理方法
var express = require('express')
// 1.使用express专门提供的路由器处理路由
var router = express.Router()// ----------------引入dao模块-------------------
// 先对dao初始化
var GirlDaoFunction = require('./node_36_dao')
// 时间格式化
var BeyondDateFormatFunction = require('./BeyondDateFormat')// ----------------首页-------------------
router.get('/',function (request,response) {// 至于请求参数可以这样:// var queryObj = request.query// ----------------查找所有------------------// 查找所有,第1个参数不写,就是查找所有GirlDaoFunction.find(function (error,girls) {if (error) {return NSLog('查询出错: ' + error)}// 使用模板引擎渲染// 注意: 模板文件默认是放在views目录下// 为此,我们在views目录下  分别为不同的业务模块创建了不同的文件夹// 如 login登录 admin后台管理 index前台首页 article文章 comment评论response.render('index/node_36_index.html',{girlArr:girls})})})// ----------------添加的表单页面-------------------
router.get('/add',function (request,response) {response.render('index/node_36_add.html')
})// ----------------增加一条记录-------------------
router.post('/insert',function (request,response) {// 1.body-parser得到objvar girlObj = request.body// NSLog(girlObj)// 1.调用girlDao写到文件数据库girlObj.pubTime = BeyondDateFormatFunction(new Date(),'yyyy-MM-dd')var newGirl = new GirlDaoFunction(girlObj)// 2.保存到数据库newGirl.save(function (error) {if (error) {// 有错误return response.status(500).send(error)}// 没有错误,跳转到首页   response.redirect('/')})
})// ----------------修改页面-------------------
router.get('/edit',function (request,response) {// 查询的girlID 不知怎么滴,首尾有引号//  "5ad42675f917fa32e250a58a"// 使用正则,把引号去掉, 如果不使用g的话,仅仅只是去掉第1个引号var pureId = request.query._id.replace(/"/g,"")// NSLog('query: ' + pureId)GirlDaoFunction.findById(pureId,function (error,girl) {if (error) {return response.status(500),send(error)}response.render('index/node_36_edit.html',{'girl': girl})})
})
// ----------------更新数据库-------------------
router.post('/update',function (request,response) {// 1.请求体 id号 (前后多了两个引号,要手动去掉)var girlID = request.body._idvar girlIDWithoutQuote = girlID.replace(/"/g,'')// 2.重新设置回去request.body._id = girlIDWithoutQuote// 3.根据id查询和更新GirlDaoFunction.findByIdAndUpdate(girlIDWithoutQuote,request.body,function (error) {if(error){// 如果保存出错了return response.status(500).send(error)}// 如果保存成功,回首页response.redirect('/')})
})// ----------------删除一条记录-------------------
router.get('/delete',function (request,response) {// 1.获取query对象中的_idvar girlID = request.query._idvar girlIDWithoutQuote = girlID.replace(/"/g,'')// 2.调用dao从数据库中删除一个对象GirlDaoFunction.findByIdAndRemove(girlIDWithoutQuote,function (error) {if (error) {// 有错误return response.status(500).send(error)}// 如果没有错误,跳转到首页return response.redirect('/')})
})// 3.在模块文件最后,导出router
module.exports = router

未完待续,下一章节,つづく

NodeJS_06_Mysql_Promise_json-server_http-server相关推荐

  1. gRPC和gRPC-Gateway的使用以及遇到的坑

    原创不易,未经允许,请勿转载. 文章目录 一.gRPC的使用 1.1 gPRC和Protobuf的安装 1.2 编写proto文件 1.3 编写服务端接口程序 1.4 编写客户端程序 二.gRPC-G ...

  2. 【Sql Server】数据库的3大服务

    在数据库SQL SERVER中,处理常用的sql server数据库引擎,还有其他3大服务,分别是集成服务,报表服务,分析服务. 集成服务商可以配置包,这里的包可以理解是数据库引擎里的用户数据库.可以 ...

  3. 【Sql Server】DateBase-自动化

    强大的SQL Server有着神奇的自动化功能,来处理一些人为处理不了的事情! 自动化功能:T-sql语言,系统命令.脚本语言.复制命令.创建角色.索引重建.报表 管理元素:作业.警报.操作员.计划 ...

  4. 【Sql Server】DateBase-触发器

    触发器是数据库中一种特殊的对象,当使用触发器时,一旦执行某个操作,就会触发执行的一段代码! 语法: Create trigger 名 On[table|view] { For after instea ...

  5. 【Sql Server】DateBase-视频总结

    最近看完了数据库视频,内容繁杂,但也不是无迹可寻! 这是第三遍关于数据库的学习了,随着一遍一遍的深入,更加了解了它的全貌,虽然现在对于数据库还不能到达熟练操作的地步,但至少放我手上不在犯怵了. SQL ...

  6. sql server登录名、服务器角色、数据库用户、数据库角色、架构区别联系

    原创链接:https://www.cnblogs.com/lxf1117/p/6762315.html sql server登录名.服务器角色.数据库用户.数据库角色.架构区别联系 1.一个数据库用户 ...

  7. 分布式TensorFlow集群local server使用详解

    通过local server理解分布式TensorFlow集群的应用与实现. ​​简介 TensorFlow从0.8版本开始,支持分布式集群,并且自带了local server方便测试. Local ...

  8. 合肥工业大学—SQL Server数据库实验十:用户及其权限管理

    用户及其权限管理 1. 创建登录名Mylog及密码 2. 创建用户user2关联登录名 3. 创建角色role1 4. 对用户user2及角色role1授权 5. 验证用户授权 6. 收回用户权限 1 ...

  9. 合肥工业大学—SQL Server数据库实验四:数据库的分离和附加

    数据库的分离和附加 1. 数据库分离 2. 数据库附加 1. 数据库分离 当SQL Server服务器运行时,该服务器上所有的数据库自动处于运行状态,而运行中的数据库文件是无法进行数据库文件的拷贝的. ...

  10. 用户自定义协议client/server代码示例

    用户自定义协议client/server代码示例 代码参考链接:https://github.com/sogou/workflow message.h message.cc server.cc cli ...

最新文章

  1. P1583 魔法照片
  2. 软件测试——等价类划分
  3. 通用印刷体识别 php,实战腾讯云ORC文字识别
  4. 怎么才能判断一个产品用户体验的好坏?
  5. html5 div css 页签,div css 实现tabs标签的思路及示例代码
  6. ASP.NET Web API 记录请求响应数据到日志的一个方法
  7. android手动亮度调节,背光闪烁,自动背光调节
  8. Windows手机开发工具与资源
  9. WordPress采集插件-WordPress文章自动采集发布
  10. UiPath安装pdf
  11. ABBYY最新版本OCR文字图像识别软件v16
  12. linux ora -03113,ORA-03113解决方法
  13. 为开发者们准备的10款超棒的jQuery视频插件
  14. 下一跳配置的原则--ensp
  15. python元组元素的提取_Python 元组
  16. Git中HEAD和ORIG_HEAD指针指的是什么
  17. 学习:SPWeb:Allusers、SiteUsers、Users和Sitegroups、Groups以及安全性编程
  18. mysql 约束 分类,MySQL约束类型及举例介绍
  19. 虚拟化服务器授权,VMware授权变相收费? 虚拟化一大障碍
  20. 视频服务器(3) RTSP地址

热门文章

  1. 软件狂人精心筛选的正版破解软件下载站大全
  2. 我的第一个lamp网站 感人故事网 上线了
  3. 《数学之美》PPT配套讲稿
  4. 利用python re提取文件中的块内容(多行)
  5. crm项目大纲,SSM回顾
  6. selenium + python处理select标签下拉框的选项
  7. php phpexcel 导入时间转换成正常时间
  8. bfo java_Java 利用BFO操作PDF文件
  9. 魔众相册系统 v1.2.0 系统内核升级,界面显示优化
  10. face++与python实现人脸识别签到(考勤)功能