开发者学堂课程【Node.js 入门与实战:封装读取data.json文件的方法】学习笔记,与课程紧密联系,让用户快速学习知识
课程地址:https://developer.aliyun.com/learning/course/588/detail/8290
封装读取data.json文件
目录:
一、被重复使用到的代码
二、代码的优化
三.封装读取data.jason文件
一、被重复使用到的代码
现接上HakerNews进行继续的书写。当前基本的新闻列表页、新闻详情页、两种添加新闻的方式均已实现,而被重复使用的代码片段也成为了代码整体看似繁杂冗长的原因。
例如:
1. 读取、写入 data.jsson 文件
在读取文件、即频繁运用到读取、写入 data.jsson 文件的代码:
//将新 list 数据再次写入 data.json 文件中
fs.writeFile(path.join(__dirname,
‘
data',
‘
data.json'),JSON.stringify(list),function(err)
{
if(err) {
}
console.log('ok' );
// 设置响应报文头,通过响应报文头告诉浏览器,执行一次页面跳转操作
//3.跳转到新闻列表页
//重定向
res.statusCode = 302;
res.statusMessage =
‘
Found
’
;
res.setHeader('Location',
‘
/
’
);
res.end();
}
);
2.写入文件
//将新的1ist数组,再次写入到data.json文件中
fs
.
writeFile(path.join(__dirname,
‘
data
’
,
‘
data. json
’
), JSON.stringify(list), function(err) {
if
(err) {
throw err;
}
console.log(
‘
ok
’
);
//设置相应文头,通过相应文投告诉浏览器,执行一次页面跳转操作
//3.跳转到新闻列表页
//重定向
res.statusCode = 302;
res.statusMessage =
‘
Found
’
res.setHeader(
‘
Location
’
,
‘
/
’
);
res.end();
}
);
二、代码的优化
为实现以上重复代码问题的解决,现需要进行的步骤为即代码的优化.
需要优化的方面
(1)读取 data.jason 文件
(2)写入 data.jason 文件
将两代码封装进一个函数之中,封装后凡是运用到读取文件、写入文件的地方都可使用此函数进行解决
三.封装读取data.jason文件
1.实例
//读取 data.jason 文件中的数据
fs.readFile(path.join(
_
_dirname,
‘
ata',
‘
data.json
’
),
‘
utf8
’
,function(err,data) {
if(e
rr
&& err.code !==
‘
ENOENT
’
) {
throw err;
}
var list - JSON.parse(data ||
‘
[]
’
);
2.问题的考虑
以如上为例,当进行封装代码操作时,需要考虑的两个问题:
1.是否需要为此代码添加参数
2.此代码是否需要返回值
3.封装代码的区别
进行当前实例中读取文件代码的封装与此前封装操作并不相同。此前所进行的封装均为同步代码,而此前的第10行:读取到数据后将此数据返回,进行数据的使用,再进行return操作将此数据放置到封装方法之外。但当前情况下,文件的读取或书写大多都是异步进行的。
4.封装读取 data.jason 文件的要点
核心-回调函数的需要
若封装的代码需要异步进行才能得到结果,则封装代码期间,此函数并不能通过return进行结果的返回,其必须通过一个return函数把被封装的此段代码中的异步结果传递而出。即:为实现得到结果的目的,包含异步操作的封装代码即使使用了封装方法也需要进行回调函数的传入,通过回调函数才可得到内部的结果。
5.实际操作
(1)首先进行代码的拷贝,以便后续操作的使用。
(2)尽管文件中的路径可作为参数进行传递,但由于此路径在当前情况下已被设定死(后续的其他方法可将其变活),暂不实现参数的传递。
//封装一个读取 data.json 的函数。进行一个名为 readNewsDate 的 function 的添加,在其之中读取 data.json 这一文件。
暂时不进行参数的填写,即假设路径被写死,将上述代码进行 control+v 进行代码的拷贝,将代码填写完整。
function readNewsDate(){
fs.readFile(path.join(__dirname,‘ata',‘data.json’),‘utf8’,function(err,data) {
if(err && err.code !== ‘ENOENT’) {
throw err;
}
var list - JSON.parse(data ||‘[]’);
)
);
return
list;
}
//以上即为读取 data.json 文件的代码的总体书写。在拿到结果 list 后,进行是否需要返回的讨论。
暂且不提 list 在此处无法被访问到的问题。假设当前 list 可以被访问,将声明放于其外,此操作也并不合适。其原因是读取文件为异步操作,当程序执行至第254行(fs.readFile(path.join(__dirname,‘ata',‘data.json’),‘utf8’,function(err,data) { 一行)时,读取文件被瞬间开启,而后nodejs底层进行文件的读取。
假设文件巨大,读取比较耗时,而程序从第254行执行完毕开启异步读取立即执行至第262行(即return list),并不会等待文件被读取完毕,故即便list被进行了外部的声明,由于list事先为 on defined,故对于有异步回调的函数,并不能通过return 的方式得到其结果。
(3)此时,若进行 return 书写的提前,同时也不可行:
252 function readNewsDate(){
253 var list
254
255 fs.readFile(path.join(__dirname,‘ata',‘data.json’),‘utf8’,function(err,data) {
256 if(err && err.code !== ‘ENOENT’) {
257 throw err;
258 }
259 var list - JSON.parse(data ||‘[]’);
260
261 return list;
262 ));
2
63
264
265 return list;
266 }
若在265行进行 return list,代表了 readNewsDate 方法的返回值,但若在261行进行 return list,代表了回调函数的返回值。当前需要的为在 readNewsDate 方法下得到返回值,并非回调函数的返回值,故,此方法更为错误。
(4)回调函数的填写:function readNewsDate(callback){
252 function readNewsDate(){
253
254
255 fs.readFile(path.join(__dirname,‘ata',‘data.json’),‘utf8’,function(err,data) {
256 if(err && err.code !== ‘ENOENT’) {
257 throw err;
258 }
259 var list - JSON.parse(data ||‘[]’);
260
261 //通过调用回调函数 callback() 将读取到的数据list,传递出去。
262 callback(list);
264 });
265
266 }
将来欲得到结果,他人调用readNewsDate时,必须传回一个回调函数,再在内部异步回调中即可得到结果。
(5)进行代码的格式化
6.测试
新建index8,其意义为:
//封装 读取 date.json文件和写入date.json文件的方法
function readNewsDate(){
fs.readFile(path.join(__dirname,‘ata',‘data.json’),‘utf8’,function(err,data) {
if(err && err.code !== ‘ENOENT’) {
throw err;
}
var list - JSON.parse(data ||‘[]’);
//通过调用回调函数 callback() 将读取到的数据list,传递出去。callback(list);
}
)
;
}
以上为封装方法的完成,现需实现实际使用方法中的调用。
(1)寻找到需要读取 date.json 文件之处:
读取点1
//读取 data.json 文件中的数据,并将读取到的数据转换为list数组
//调用 readNewsDate,传入一个回调函数进来,往后回调函数将在readNewsDate 内部传入一个list数据,意味着在此前一大串读取数据的代码只需要调用一个函数即可。
在函数中即可得到读取结果。即可以进行步骤二的直接复制
function readNewsDate(
list
)
//2.在服务器端使用模板引擎,将 list 中的数据和 index.html 文件中的内容结合渲染给客户端
//读取 index.html
res.render(path. join(__ dirname, 'views', ' index.html'), { list: list});
});
//以下的步骤不再需要fs.writeFile(path.join(__dirname,‘data',‘data.json'),JSON.stringify(list),function(err) {
if(err) {
}
//此部分的代码只进行了两个操作:
(1)读取 date.json 中的数据,拿到list
(2)将 list 进行传输,引擎渲染成功。
故,此部分代码可以进行删除,删减过后即得到:
function readNewsDate(list)
res.render(path. join(__ dirname, 'views', ' index.html'), { list: list});
});
查看函数内部代码:
//封装一个读取 data.json 文件的函数 function readNewsData(callback){
fs.writeFile(path.join(__dirname,‘data',‘data.json'),
‘
utf8’,function(err,data) {
throw err;
}
var list - JSON.parse(data ||‘[]’);
//通过调用回调函数 callback() 将读取到的数据 list 传递至回调函数的参数
callback(list);
});
}
7.首页的测试
进行 index8 的执行
λ node index8.js
h
ttp://locationhost:9090
于浏览器中输入网址,首页正常显示,同时服务器未报错误
至此,证明分装读取 date.json 方法的实行完毕。
读取点2
//1.获取当前用户请求的新闻 id
//ur
10bj.query.id
//2.读取 date.jason 文件中的数据,根据id找到对应新闻
//调用 readNewsDate
readNewsDate(function(
list
_
news
) {
//首先通过 readNewsDate 拿到date.json 中的结果
//进行数据的复制,再进行list_news的相关修改
var model---null;
//循环 1ist news 中的数据,找到和id值相等的数据
for(var i - 0; i
<
s list_news length;i++){
//判断集合中是否哦以后于用户提交的id相等的数据
if(list_ news[i].id.toString()..url0bj.query.id){
//若找到相等的新闻入则将其记录下来
model - list news[i];
break;
}
{
//通过循环进行判断,再进行找到和找不到的分别操作
1f.(model){
//3.使用 res.render()函数进行模板引擎的渲染
res.render(path.join( dirname,
‘
views
’,
'details.html'),f item:mode
l
});
} else {
res.end('No Such Item');
}
}
);
// 以下部分可直接删去
fs.readFile(path.join(
dirname,
‘
data
’,‘
data.json
’
),
‘
utf8
’
,function(err,data) {
if.(err-&&.err.code
!=
=
‘
ENOENT
’
){
thro
w
err;
}
最终结果进行格式化后为:
//将查看新闻代码路由的代码同样变成了回调函数来处理
readNewsDate(fuction(list_news) {
var model---null;
for(var i - 0; i < s list_news length;i++){
if(list_ news[i].id.toString()..url0bj.query.id){
model - list news[i];
break;
}
{
1f.(model){
res.render(path.join( dirname,‘views ’,'details.html'),f item:model});
} else {
res.end('No Such Item');
}
});
测试:
进行 index8 的执行
λ
node index8.js
http://locationhost:9090
在网页中任选一条新闻进行查看:
至此,证明分装读取date.json方法的实行完毕。