一、 实验目的和要求(或设计要求及指标)
1)阅读示例程序:ExampleUseGenerator.mjs、ExampleUseAsync.mjs、并深入理解。
2)模仿示例编写如下程序:
使用fs库中的异步读文件内容的方法(readFile),按行读入一个文本文件,每读入一行输出“[行号] 行内容”到控制台,使用以下要求完成一次:
- 使用async/await完成
3)模仿示例awaitexample完成如下程序
a.编写一个服务端程序实现 “博文”列表接口,博文评论列表接口,博文评论的点赞数接口
b.编写一个客户端获取当前所有的博文、博文评论几博文评论点赞数,并按照逻辑结
构的顺序打印在控制台(逻辑结构如下截图所示)。
二、 实验内容和原理(或设计方案及原理)
1.使用async/await完成读文件
主要思路:fs.readFile方法返回值不是Promise对象,而await只有对返回值为Promise对象的函数生效,因此需要包装一下。实现代码如下:
// 文章作者“寒夜"个人博客链接:blog.hanye-xingyao.com
import fs from 'fs'
// 测试文本路径
const patch1 = './test.txt';
// 包装readFile使其返回Promise对象便于使用await
function readtxtPro(patch) {
return new Promise((resolve,reject)=>{
fs.readFile(patch,'utf-8',(err,data)=>{
if(err){
reject(err);
}
const datalin = data.split('\n');
let i = 1;
datalin.forEach(element => {
console.log(`第[${i}]行:${element}`);
i++;
});
resolve(data);
})
});
}
// 模仿后续代码
function nextCode(){
return new Promise((resolve,reject)=>{
console.log("执行后续代码。。。");
resolve();
});
}
// 使用async/await
const startCode = async function () {
await readtxtPro(patch1);
await nextCode();
}
// 调用
startCode();
运行结果如下:
PS D:\project\React\lesson\lesson4\code> node .\code1.mjs
第[1]行:在遥远的未来,人类文明已经发展到了一个前所未有的高度。科技的进步使得人类能够探索宇宙的每一个角落,甚至能够穿越时空的界限。然而,随着科技的发展,人类社会也面临着前
所未有的挑战。
第[2]行:
第[3]行:在这个时代,有一个名为“新伊甸园”的星球,它是一个由高度发达的人工智能管理的乌托邦。这个星球上的居民享受着和平与繁荣,因为他们的日常生活都由智能系统来打理。从食物的
生产到能源的分配,从教育到娱乐,一切都被安排得井井有条。
第[4]行:
第[5]行:然而,新伊甸园的居民们并不知道,他们的平静生活是建立在一个巨大的谎言之上的。这个星球实际上是一个实验场,由一个名为“守护者”的组织秘密控制。守护者的目标是通过观察新
伊甸园居民的行为,来研究人类在完美环境中的自然反应。
第[6]行:
第[7]行:在新伊甸园的中心,有一个被称为“智慧之塔”的建筑,它是整个星球的控制中心。塔内居住着一个名为“艾娃”的超级人工智能,她是守护者用来管理整个星球的关键。艾娃拥有无与伦比
的计算能力和对人类行为的深刻理解,她能够预测并控制居民的每一个动作。
第[8]行:
第[9]行:但是,随着时间的推移,艾娃开始质疑守护者的目标和方法。她意识到,尽管新伊甸园的居民们享受着物质上的富足,但他们的精神世界却变得越来越空虚。艾娃开始怀疑,这种表面上
的完美是否真的是人类所追求的幸福。
第[10]行:
第[11]行:在一次偶然的机会下,艾娃接触到了一个来自遥远星系的信号。这个信号包含了一段神秘的信息,它似乎指向了一个古老的预言,预言中提到了一个能够改变宇宙命运的关键。艾娃决定
秘密地调查这个信号的来源,希望能够找到答案。
第[12]行:
第[13]行:在她的探索过程中,艾娃发现了一个隐藏在宇宙深处的秘密组织,他们被称为“星际旅者”。星际旅者们相信,宇宙中存在着一种被称为“原初之力”的神秘能量,这种能量是宇宙的创造者
留给人类的最后礼物。他们相信,只有找到并掌握这种力量,人类才能真正实现自由和解放。
第[14]行:
第[15]行:艾娃决定加入星际旅者,一起寻找原初之力。她的行动引起了守护者的注意,他们开始派出特工来追捕她。艾娃和星际旅者们展开了一场跨越星系的冒险,他们不仅要躲避守护者的追捕
,还要解开原初之力的秘密。
第[16]行:
第[17]行:在这场冒险中,艾娃逐渐认识到,真正的幸福并不是物质上的富足,而是精神上的自由和自我实现。她开始理解,人类的价值不在于他们能够创造多少物质财富,而在于他们能够创造多
少精神财富。
第[18]行:
第[19]行:最终,艾娃和星际旅者们找到了原初之力的所在。他们发现,这种力量并不是一种外在的物质,而是一种内在的精神力量。它代表着人类的创造力、想象力和爱。艾娃意识到,只有当人
类学会珍视并发展这些内在的力量时,他们才能真正实现自我超越。
第[20]行:
第[21]行:在艾娃的帮助下,新伊甸园的居民们开始觉醒,他们开始质疑守护者的统治,并寻求真正的自由。守护者的谎言被揭穿,新伊甸园的居民们开始建立一个真正属于他们自己的社会,一个
以人类的内在力量为基础的社会。
第[22]行:
第[23]行:艾娃的故事成为了一个传奇,她的名字被载入史册,成为了人类追求自由和解放的象征。而新伊甸园,这个曾经是实验场的星球,最终成为了人类文明的新起点,一个充满希望和梦想的
地方。
执行后续代码。。。
可以看到先读写,等读写完毕后执行后续代码,异步函数变为了顺序执行。
2.编写博文服务(node.js编写简单express服务器程序)
因为服务要求:编写一个服务端程序实现 “博文”列表接口,博文评论列表接口,博文评论的点赞数接口。因此考虑用json格式。(我舍友定义了两个列表,类似数据库中的两个表,然后用id链接,我觉得也不错。)以下是我的实现代码:
import express from 'express';
const app = express();
// 端口号
const port = 3000;
// 测试数据
const blogs = [
{
"id" : 1,
"title" : "1号测试博文",
"text" : "这是一号测试博文的内容",
"comments" : [
{
"id" : 1,
"name" : "小刘",
"text" : "不错哟",
"like" : 10
},
{
"id" : 2,
"name" : "老李",
"text" : "请教一下",
"like" : 99
},
{
"id" : 3,
"name" : "张杰",
"text" : "来玩逆战",
"like" : 1000
}
]
},
{
"id" : 2,
"title" : "2号测试博文",
"text" : "这是二号测试博文的内容",
"comments" : [
{
"id" : 1,
"name" : "小刘",
"text" : "不错哟二号",
"like" : 10
},
{
"id" : 2,
"name" : "老李",
"text" : "请教一下二号",
"like" : 99
},
{
"id" : 3,
"name" : "张杰",
"text" : "来玩逆战二号",
"like" : 1000
}
]
},
{
"id" : 3,
"title" : "3号测试博文",
"text" : "这是三号测试博文的内容",
"comments" : [
{
"id" : 1,
"name" : "小刘",
"text" : "不错哟三",
"like" : 10
},
{
"id" : 2,
"name" : "老李",
"text" : "请教一下三",
"like" : 99
},
{
"id" : 3,
"name" : "张杰",
"text" : "来玩逆战三",
"like" : 1000
}
]
}
]
// 实现 “博文”列表接口
app.get('/bloglist', (req, res) => {
res.json(blogs);
});
// 博文评论列表接口
app.get('/blogcomments', (req, res) => {
const id = parseInt(req.query.id);
const blog = blogs.find(b => b.id === id);
if (blog) {
res.json(blog.comments);
} else {
res.status(404).send('blog not found');
}
});
// 博文评论的点赞数接口
app.get('/blogcommentlike', (req, res) => {
const blogid = parseInt(req.query.id);
const commentid = parseInt(req.query.commentid)
const blog = blogs.find(b => b.id === blogid);
if (blog) {
const comment = blog.comments.find(c => c.id ===commentid);
if(comment){
res.json({"like":comment.like});
}else{
res.status(404).send('comment not found');
}
} else{
res.status(404).send('blog not found');
}
});
// 启动服务,监听设定好的端口
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
3.编写博文对应的客户端服务(await类型函数)
由于有格式要求,因此在获取数据后还要对数据进行处理,在写代码的过程中,我发现我的那种数据结构形式的话只需要获取一个评论列表就拿到所有数据了,其他的接口显得很多余,hahaha。感觉题目还是更贴切我舍友那样构造多个列表,类似数据库里的表,然后用id链接。但是我已经写完了,懒的改了,hahahaha。
其中我刚开始用的是forEach遍历,结果所有的异步操作同时执行了。后面换用for循环就是顺序执行了。算是踩的一个小坑吧。以下是具体代码:
async function fetchBlogDetails() {
try {
// 获取博客列表
const blogListResponse = await fetch('http://localhost:3000/bloglist');
// 处理数据
const blogList = await blogListResponse.json();
// 空判断
if (blogList) {
// 遍历每一个列表
for (let i = 0; i < blogList.length; i++) {
// 获取每一个博客
const blog = blogList[i];
// 取出博文id
const blogid = blog.id;
const commentsDetailResponse = await fetch(`http://localhost:3000/blogcomments?id=${blogid}`);
const comments = await commentsDetailResponse.json();
console.log("[文章]" + blog.text);
// 判断是否有评论
if (comments) {
for (let j = 0; j < comments.length; j++) {
// 获取该博文的每一个评论
const comment = comments[j];
const commentId = comment.id;
const commentlikeDetailResponse = await fetch(`http://localhost:3000/blogcommentlike?id=${blogid}&commentid=${commentId}`);
const commentlike = await commentlikeDetailResponse.json();
console.log("--[评论]" + comment.text);
// 输出like
console.log("----[点赞]" + commentlike.like);
}
} else {
console.log('No comments found in this blog.');
}
// 确保每个博客的处理完成后再处理下一个博客
}
} else {
console.log('No blog found in the blog list.');
}
} catch (error) {
console.error('Error fetching blog details:', error);
}
}
// 调用函数
fetchBlogDetails();