第一节说了,如果不做数据的持久化,服务重启后,我们之前做的所有操作就都失效了。
但怎么做持久化呢?最原始的方式当然是文件了。
新建.gitignore
根目录下新建一个.gitignore文件,把data文件夹(我们的数据文件user.json就放它下面)放进去,它不需要提交。
data
修改deno.jsonc文件
因为我们要写入和读取文件,所以要额外增加两个权限(--allow-write --allow-read)。
{
"tasks": {
"dev": "deno run --allow-net --allow-write --allow-read --watch src/main.ts"
}
}
修改src/user.service.ts
class UserService {
users: User[] = [
{ id: 1, author: "张三", age: 18 },
];
constructor() {
Deno.mkdir("data").catch(() => null);
}
async getAll(): Promise<User[]> {
const usersStr = await Deno.readTextFile("data/user.json").catch(() =>
null
);
if (usersStr) {
return JSON.parse(usersStr);
}
return this.users;
}
async getUserById(id: number) {
const users = await this.getAll();
return users.find((user) => user.id === id);
}
private saveToFile(users: User[]) {
return Deno.writeTextFile("data/user.json", JSON.stringify(users, null, 2));
}
async addUser(user: Omit<User, "id">) {
const users = await this.getAll();
const id = users.length + 1;
const newUser = {
...user,
id,
};
users.push(newUser);
await this.saveToFile(users);
return newUser;
}
async removeUser(id: number) {
const users = await this.getAll();
const newUsers = users.filter((user) => user.id !== id);
await this.saveToFile(newUsers);
}
async updateUser(id: number, user: Omit<User, "id">) {
const users = await this.getAll();
const oldUser = users.find((u) => u.id === id);
if (!oldUser) {
throw new Error(`user not found`);
}
Object.assign(oldUser, user);
await this.saveToFile(users);
}
}
可以看到,重点是增加了一个方法:
private saveToFile(users: User[]) {
return Deno.writeTextFile("data/user.json", JSON.stringify(users, null, 2));
}
getAll方法是读取这个文件内容,不存在时才降级为初始化的数据。
注意:增加、修改、删除都是在它的基础上,修改之后,再覆盖原文件。
因为读写文件我们用的异步的API,所以返回结果都是个Promise。
时刻记住一点,I/O是影响性能的一个关键点,尤其是同步I/O,更会阻塞进程。在使用JavaScript开发时,能用异步就用异步。
修改src/main.ts
正因为user.service.ts中每个方法都变成了异步的,main.ts上层调用时,也都需要把await加上。
router
.get("/", (context) => {
context.response.body = "hello world";
})
.get("/user", async (context) => {
context.response.body = await userService.getAll();
})
.get("/user/:id", async (context) => {
const id = Number(context.params.id);
const user = await userService.getUserById(id);
if (user) {
context.response.body = user;
} else {
context.response.status = 404;
context.response.body = "user not found";
}
})
.post("/user", async (context) => {
const result = context.request.body({
type: "json",
});
const value = await result.value;
const user = await userService.addUser(value);
context.response.body = user;
})
.put("/user/:id", async (context) => {
const id = Number(context.params.id);
const result = context.request.body({
type: "json",
});
const value = await result.value;
try {
await userService.updateUser(id, value);
context.response.body = "update ok";
} catch (e) {
context.response.status = 400;
context.response.body = e.message;
}
})
.delete("/user/:id", (context) => {
const id = Number(context.params.id);
userService.removeUser(id);
context.response.body = "delete ok";
});
验证
当在F12控制台增加一条数据
fetch("/user", {
method: "post",
headers: { "content-type": "application/json" },
body: JSON.stringify({ author: "李四", age: 10 }),
});
就能看到data文件夹下面生成了一个user.json文件,内容是:
[
{
"id": 1,
"author": "张三",
"age": 18
},
{
"author": "李四",
"age": 5,
"id": 2
}
]
同样的,修改或删除,都会引发这个文件的变化。
作业
思考下,如果使用localStorage来持久化我们的数据,该怎么修改呢?