NodeJS_06_Mysql_Promise_json-server_http-server
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相关推荐
- gRPC和gRPC-Gateway的使用以及遇到的坑
原创不易,未经允许,请勿转载. 文章目录 一.gRPC的使用 1.1 gPRC和Protobuf的安装 1.2 编写proto文件 1.3 编写服务端接口程序 1.4 编写客户端程序 二.gRPC-G ...
- 【Sql Server】数据库的3大服务
在数据库SQL SERVER中,处理常用的sql server数据库引擎,还有其他3大服务,分别是集成服务,报表服务,分析服务. 集成服务商可以配置包,这里的包可以理解是数据库引擎里的用户数据库.可以 ...
- 【Sql Server】DateBase-自动化
强大的SQL Server有着神奇的自动化功能,来处理一些人为处理不了的事情! 自动化功能:T-sql语言,系统命令.脚本语言.复制命令.创建角色.索引重建.报表 管理元素:作业.警报.操作员.计划 ...
- 【Sql Server】DateBase-触发器
触发器是数据库中一种特殊的对象,当使用触发器时,一旦执行某个操作,就会触发执行的一段代码! 语法: Create trigger 名 On[table|view] { For after instea ...
- 【Sql Server】DateBase-视频总结
最近看完了数据库视频,内容繁杂,但也不是无迹可寻! 这是第三遍关于数据库的学习了,随着一遍一遍的深入,更加了解了它的全貌,虽然现在对于数据库还不能到达熟练操作的地步,但至少放我手上不在犯怵了. SQL ...
- sql server登录名、服务器角色、数据库用户、数据库角色、架构区别联系
原创链接:https://www.cnblogs.com/lxf1117/p/6762315.html sql server登录名.服务器角色.数据库用户.数据库角色.架构区别联系 1.一个数据库用户 ...
- 分布式TensorFlow集群local server使用详解
通过local server理解分布式TensorFlow集群的应用与实现. 简介 TensorFlow从0.8版本开始,支持分布式集群,并且自带了local server方便测试. Local ...
- 合肥工业大学—SQL Server数据库实验十:用户及其权限管理
用户及其权限管理 1. 创建登录名Mylog及密码 2. 创建用户user2关联登录名 3. 创建角色role1 4. 对用户user2及角色role1授权 5. 验证用户授权 6. 收回用户权限 1 ...
- 合肥工业大学—SQL Server数据库实验四:数据库的分离和附加
数据库的分离和附加 1. 数据库分离 2. 数据库附加 1. 数据库分离 当SQL Server服务器运行时,该服务器上所有的数据库自动处于运行状态,而运行中的数据库文件是无法进行数据库文件的拷贝的. ...
- 用户自定义协议client/server代码示例
用户自定义协议client/server代码示例 代码参考链接:https://github.com/sogou/workflow message.h message.cc server.cc cli ...
最新文章
- P1583 魔法照片
- 软件测试——等价类划分
- 通用印刷体识别 php,实战腾讯云ORC文字识别
- 怎么才能判断一个产品用户体验的好坏?
- html5 div css 页签,div css 实现tabs标签的思路及示例代码
- ASP.NET Web API 记录请求响应数据到日志的一个方法
- android手动亮度调节,背光闪烁,自动背光调节
- Windows手机开发工具与资源
- WordPress采集插件-WordPress文章自动采集发布
- UiPath安装pdf
- ABBYY最新版本OCR文字图像识别软件v16
- linux ora -03113,ORA-03113解决方法
- 为开发者们准备的10款超棒的jQuery视频插件
- 下一跳配置的原则--ensp
- python元组元素的提取_Python 元组
- Git中HEAD和ORIG_HEAD指针指的是什么
- 学习:SPWeb:Allusers、SiteUsers、Users和Sitegroups、Groups以及安全性编程
- mysql 约束 分类,MySQL约束类型及举例介绍
- 虚拟化服务器授权,VMware授权变相收费? 虚拟化一大障碍
- 视频服务器(3) RTSP地址