1.异步回调和Promise使用
我们先看一个异步数据读取的过程:
const fs = require('fs')
const path = require('path')
//resolve可以通过拼接多个步骤的方式把文件名拼出来,__dirname是指当前目录
const fullFileName = path.resolve(__dirname,'files','a.json')
fs.readFile(fullFileName,(err,data) => {
if(err){
console.error(err)
return
}
//fs.readFile 读出来的data数据是二进制的流文件,所以要经过toString转换
console.log(data.toString())
})
我们想封装这个读取文件的函数,并测试多次回调:
//数据a.json b.json c.json是一个嵌套关系
a.json
{
"next": "b.json",
"msg": "this is a"
}
b.json
{
"next": "c.json",
"msg": "this is b"
}
c.json
{
"next": null,
"msg": "this is c"
}
// callback 方式获取一个文件的内容
function getFileContent(fileName, callback) {
const fullFileName = path.resolve(__dirname, 'files', fileName)
fs.readFile(fullFileName, (err, data) => {
if (err) {
console.error(err)
return
}
callback(
JSON.parse(data.toString())
)
})
}
// 测试 callback-hell (aData是参数,上面的JSON.parse(data.totring是实参,aData是形参)。)
getFileContent('a.json', aData => {
console.log('a data', aData)
getFileContent(aData.next, bData => {
console.log('b data', bData)
getFileContent(bData.next, cData => {
console.log('c data', cData)
})
})
})
Promise对于多次回调的解决方案
// 用 promise 获取文件内容
function getFileContent(fileName) {
const promise = new Promise((resolve, reject) => {
const fullFileName = path.resolve(__dirname, 'files', fileName)
fs.readFile(fullFileName, (err, data) => {
if (err) {
reject(err)
return
}
resolve(
JSON.parse(data.toString())
)
})
})
return promise
}
getFileContent('a.json').then(aData => {
console.log('a data', aData)
return getFileContent(aData.next)
}).then(bData => {
console.log('b data', bData)
return getFileContent(bData.next)
}).then(cData => {
console.log('c data', cData)
})
async/await同步形式解决多次回调
function getFileContent(fileName) {
const promise = new Promise((resolve, reject) => {
const fullFileName = path.resolve(__dirname, 'files', fileName)
fs.readFile(fullFileName, (err, data) => {
if (err) {
reject(err)
return
}
resolve(
JSON.parse(data.toString())
)
})
})
return promise
}
async function readFileData() {
// 同步写法
try {
const aData = await getFileContent('a.json')
console.log('a data', aData)
const bData = await getFileContent(aData.next)
console.log('b data', bData)
const cData = await getFileContent(bData.next)
console.log('c data', cData)
} catch (err) {
console.error(err)
}
}
readFileData()
// async await 要点:
// 1. await 后面可以追加 promise 对象,获取 resolve 的值
// 2. await 必须包裹在 async 函数里面
// 3. async 函数执行返回的也是一个 promise 对象
// 4. try-catch 截获 promise 中 reject 的值
Promise的实例的then方法是定义在原型对象Promise.prototype上的,then方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数,then方法返回的是一个新的Promise实例,因此可以采用链式写法,如下,前一个回调函数的返回结果会作为参数传递给下一个回调函数。
//数据a.json b.json c.json是一个嵌套关系
a.json
{
"next": "b.json",
"msg": "this is a"
}
b.json
{
"next": "c.json",
"msg": "this is b"
}
c.json
{
"next": null,
"msg": "this is c"
}
getFileContent('a.json').then(aData => {
console.log('a data', aData)
return getFileContent(aData.next)
}).then(bData => {
console.log('b data', bData)
return getFileContent(bData.next)
}).then(cData => {
console.log('c data', cData)
})
promise 的then方法默认情况下返回一个resolve状态的新的promise,而且resolve函数的参数是then里面return的值,所以最终结果是返回一个promise,resolve用 SuccessModel格式化了的值
const result = getList(author,keyword)
return result.then( listData => {
return new SuccessModel(listData)
})
2.MySQL操作
sql增删改查:
1、增: insert into 表名 ( 字段1,字段2 ) values ( 'a','b' );
2、删:delete from 表名 where 字段名 ='ab';
3、改: update 表名 set 字段名='ab' where ...;
4、 查:select * from 表名;
我们使用MySQL语句后返回的数据格式:
select * from users
//输出结果
[
RowDataPacket {
id: 1,
username: 'yangyang',
password: '123321',
realname: '洋洋'
},
RowDataPacket {
id: 2,
username: 'xie',
password: '123321',
realname: '谢'
}
]
更新数据显示结果:
3.数据库中vachar和text/longtext区别
varchar和text/longtext都可以用来存储文本格式,那么有什么区别?
1、char,存定长,速度快,存在空间浪费的可能,会处理尾部空格,上限255。
2、varchar,存变长,速度慢,不存在空间浪费,不处理尾部空格,上限65535,但是有存储长度实际65532最大可用。
3、text,存变长大数据,速度慢,不存在空间浪费,不处理尾部空格,上限65535,会用额外空间存放数据长度,顾可以全部使用65535。
总结:
经常变化的字段用varchar;
知道固定长度的用char;
尽量用varchar;
超过255字节的只能用varchar或者text;
能用varchar的地方不用text;
能够用数字类型的字段尽量选择数字类型而不用字符串类型的(电话号码),这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接回逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
参考文章:
https://www.cnblogs.com/billyxp/p/3548540.html
https://blog.csdn.net/mjshldcsd/article/details/78541323
4.利用模板文本进行SQL语句拼接
//之前的SQL拼接
var sql = "delete from users where id = " + uid;
//模板文本的SQL拼接
const getList = (author,keyword) => {
//where 1=1 是为了保证拼接sql语句正确,因为如果没有author/keyword,整个语句也不会错。
let sql = `select * from myblog where 1=1`
if(author){
sql += ` and author='${author}' `
}
if(keyword){
sql += ` and title like '%${keyword}%' `
}
sql += ` order by createtime desc; `
//返回promise
return exec(sql)
}
5.整理下整个处理流程
conf/db.js配置好dev和production环境下,数据库配置,方便直接调用。
db/mysql.js利用上面配置好的参数,然后定义统一的sql执行函数,参数为sql,这个sql由外部传入。返回一个Promise实例。
controller中的blog.js和user.js就可以调用mysql.js中的统一定义的函数,定义getList,getDetail,newBlog,updateBlog,delBlog,loginCheck等函数,每个函数都有sql语句,调用传入的exec函数,exec(sql)
,返回的是Promise实例。
router中的blog.js和user.js就可以通过传入参数,调用getList,getDetail,newBlog,updateBlog,delBlog,loginCheck,返回的是SQL语句执行的结果,是Promise实例,所以可以进行.then操作,利用model中的resModel对数据进行加工,返回一个特定格式的数据。
app.js通过调用定义的路由,返回数据res.end(JSON.stringify(blogData))
。app.js导出回调函数。
bin中www.js再调用app.js中的回调函数。