这是我参与「第四届青训营 」笔记创作活动的第2天
我们团队选择了“仿掘金官网”的题目作为大项目。
在前期的开发中,我们使用的Java的SpringMVC来做后端,但由于我们团队只有负责后端的那一个同学会Java,所以开发,调试,排错,以及最后与我这个“运维”对接上线都存在很多不便的地方。所以我就决心参照原本的Java实现,用nodejs重写一遍项目后端。
需求提出
写后端的细节不表,开发完成后,负责前端的同学提了个需求,就是能否在返回的文章列表里面带上作者名字?
这里不得不说我们的数据库的结构了,数据库是有两个表,分别是文章表和用户表,每一篇文章里都有用户的ID,用户的ID可在用户表里找到用户的名称。
最初该接口的实现是根据id直接去文章表里请求就行了,返回值就是请求的结果。
router.get('/queryAllArticle', function (req, res, next) {
query('SELECT id,title,intro,time,author,tag,visit FROM article ORDER BY RAND() LIMIT 10', [], (err, result) => {
if (err) {
res.status(500);
res.render('error');
}
else { res.send(result); }
});
});
需求实现
其实现在回过头来看,要实现这个需求只需要在SQL语句上做小小的改动就行了。只需改成:
SELECT a.id,a.title,a.intro,a.time,a.author,a.tag,a.visit,p.nickname FROM article a,people p where a.author=p.id;
可当时我连着开发了几天的后端,头也昏昏沉沉的,连数据库的基本操作都忘了,所以我想出来的解决方法是,根据每一个出来的作者id,再在people表中查到作者名字,再添加到结果中返回。
于是,初步的代码是这样:
result.forEach(function (val, index) {
query('SELECT nickname FROM people where id = ?', [val.author], (err, result) => {
if (err) { res.status(500); res.send('error'); }
else {
//将结果的nickname加入result中
}
})
})
}
res.send(result)
咋一看没有任何问题,但是,这个query是个异步函数!也就是可能第一个结果还没出来,下面的send就执行了,于是什么也没有发生。
于是,我们的主角,Promise,出场了。
ES6 中的 Promise 是异步编程的一种方案。从语法上讲,Promise 是一个对象,它可以获取异步操作的消息。
但是,要怎样才能确保每一个操作都能完成呢?根据resolve的特性,我们可以通过设置flag的方式来实现。
最终代码如下:
let AddAuthorName = (result) => {
return new Promise((resolve, reject) => {
if (!result.length) { resolve(result); }
let flag = result.length;
result.forEach(function (val, index) {
query('SELECT nickname FROM people where id = ?', [val.author], (err, res) => {
if (err) { reject(err) }
else {
val.authorName = res[0].nickname;
result[index] == val;
flag--;
if (!flag) {
resolve(result);
}
}
})
})
})
}
router.get('/queryAllArticle', function (req, res, next) {
query('SELECT id,title,intro,time,author,tag,visit FROM article ORDER BY RAND() LIMIT 10', [], (err, result) => {
if (err) {
res.status(500);
res.send('error');
}
else {
AddAuthorName(result).then((val) => { res.send(val); }, (err) => { res.status(500); res.send('error')})
}
});
});
后记
其实写完了才发现,本来这篇文章是要写Promise的,结果写到一半才发现在数据库上可以有更优解。或许这就是写笔记的意义吧,在回顾过去的知识的同时迸发新的思考。