1.引言
随着自己对node后端的了解加深,发现自己对于JavaScript的高级用法需要更加深入的理解,否则永远都是码砖,难有提升。于是总结了如下一个在javascript编程里面比较常用的例子作以理解并分享,如果不对,欢迎批评指正。
2.问题溯源
使用koa框架,某接口需要查询数据库数据,查询完数据之后需要进一步处理,最后使用koa的ctx.body
返回请求数据。
3.问题解决
直接放代码如下(当时因为项目紧急,核心部分借鉴的大佬的代码):
//第一段代码:使用单例模式进行数据库的长连接
//归属文件:/config/connect-mysql.js
const mysql = require("mysql");
module.exports=class MysqlConnect {//利用单例模式处理数据库的连接
constructor() {
if (!MysqlConnect.instance) {
MysqlConnect.instance = mysql.createConnection({
connectionLimit: 20,
host: 'localhost',
port: 3306,
user: 'zhangsan',
password: 'admin123',
database: 'easyclothing'
});
MysqlConnect.instance.connect((err) => {
console.log("MySQL数据库连接成功!")
});
}
return MysqlConnect.instance;
}
}
//第二段代码:查询数据库,数据查询完成后调用回调函数
//归属文件:/models/tool.js
const MysqlConnect = require("../config/connect-mysql");
const mysqlDB = new MysqlConnect();
module.exports=function getToolList(callback) {
const promise = new Promise((resolve, reject) => {
const sql = "select * from tool";
mysqlDB.query(sql, (err, result) => {
if (err) {
console.log("tool数据表查询失败,原因:", err);
reject(err);
}
resolve(result);
})
});
promise.then((res) => {
callback(res);
});
promise.catch((err) => {
console.log("函数调用失败!", err);
})
}
//第三段代码:接受回调数据并响应用户请求
//归属文件:/router/tool.js(与代码无关)
const getToolList = require("../models/tool");
module.exports = async (ctx) => {
//代码的执行顺序说明:Promise正常执行,然后是then,最后是setTimeout
//async:用于声明函数是一个异步函数,确保返回一个Promise对象,
//下面的使用主要是提高代码的优雅度(本身就有Promise 返回)
async function delay(time) {
return new Promise((resolve, reject) => {
function callback(res) {
resolve(res);
}
setTimeout(() => {
getToolList(callback);
}, time);
});
}
//await:用于等待该异步函数执行完成
await delay(0).then((toolList) => {
ctx.body = {
data: toolList
}
});
};
4.给出自己的理解
虽然自己也曾写过async、await以及浏览器事件循环机制相关的文章总结,但是事实证明使用起来还是有些生硬,解释第三段代码:
(1)async关键字
,更像是为了方便快速使用await
获取一个Promise 的成功返回的数据;保证函数最终返回的是一个Promise 数据,如果不是Promise数据,那么封装成一个Promise 数据,如果返回的已经是Promise,那么不变;
(2)在上述代码中,使用await
是为了与最外层的async
配套,而不是async delay
函数,async 的作用可以理解成提高代码的“优雅度”或者说是可阅读性。代码首先执行delay函数,然后将time=0
参数传入,获取到一个Promise对象,具体内容如下:
new Promise((resolve, reject) => {
function callback(res) {
resolve(res);
}
setTimeout(() => {
getToolList(callback);
}, 0);
});
然后代码的.then
函数会等待处于pending
状态的Promise
进入resolve
态,直到resolve
执行也就是数据处理完毕才调用接下来的部分,最后也就成功返回想要的数据。
(3)问题来了,好端端的为什么要是用setTimeout
这个不常用的工具呢,其实,还是为了使内部依然是异步调用,处于这个假设,代码修改如下依然可以正常运行,得证!:
async function delay(time) {
return new Promise((resolve, reject) => {
function callback(res) {
resolve(res);
}
// setTimeout(() => {
// getToolList(callback);
// }, time);
(async function test() {
getToolList(callback);
}());
});
}
(4)进一步分析,这里的async
其实可以不要,因为代码顺序执行,所以可以再简化:
async function delay(time) {
return new Promise((resolve, reject) => {
function callback(res) {
resolve(res);
}
// setTimeout(() => {
// getToolList(callback);
// }, time);
getToolList(callback);
});
}
最终得出:大佬给的代码的setTimeout其实可以省略,如果不明白代码的执行流程那么,说真的,很可能会由于改动后代码运行错误,到处瞎归因,哈哈哈!