Async 和 Await
本课属于 Coddy Node.js 学习旅程的“Node.js 基础”单元。第 23 课,共 33 课。
一连串 .then 调用的阅读顺序,和你对步骤的理解不同:读取,然后解析,再保存。
在 async 函数中,await 会暂停执行,直到 promise 完成,并返回它的值。如果 promise 失败,就会在此处抛出异常,因此可以用 try 和 catch 处理。在模块中,也可以在顶层使用 await。
import { readFile } from 'node:fs/promises';
const loadConfig = async () => {
try {
return JSON.parse(await readFile('config.json', 'utf8'));
} catch {
return {};
}
};
const config = await loadConfig();
console.log(config.port ?? 3000);async 函数总是返回一个 promise,所以调用它的代码也要使用 await。如果忘了加 await,你得到的就会是 promise 本身 Promise { <pending> },而不是它的值。
挑战
简单这一步会打开课程中准备好的命令行笔记工具项目,而不是你在 Promises 中的项目文件(包括 count.js)。你之前的工作仍在它自己的课中。编辑 store.js 之前,请先阅读提供的文件。这份副本包含基于 promise 的笔记读取器及其错误处理。
store.js 现在使用 promise 版本的 readFile 和 writeFile,它的方法也都是 async。但目前还没有任何地方等待这些 promise 完成,所以每个命令都会出错。在 promise 必须完成后才能进行下一步的地方添加 await。
- 在
store.js的load中,等待readFile完成后,再让JSON.parse使用文本。 - 在
store.js中,load是async,因此它会返回一个 promise。在 store 设置notes的地方等待它。模块可以在顶层,也就是任何函数之外使用await。 - 在
store.js中,在save里等待writeFile,并在add和remove中等待this.save()。 - 在
notes.js中,store.add和store.remove现在都是async。在add和done分支中等待它们,这样n和removed保存的就是值,而不是 promise。
这样总共要添加 7 个 await。之后每个命令都会像以前一样正常工作。list 会显示 notes.json 中的笔记。初始的两条笔记还在时,add Buy bread 会打印 Saved note 3.,接着运行 done 1 会打印 Done: Buy milk。
试试看:先不要做任何更改,在 $ node notes.js 后面的输入框中输入 list。你会看到 notes.json is damaged: ...,但文件本身没有问题:传给 JSON.parse 的是一个 promise,而不是文件文本。完成更改后,list 会再次显示笔记。然后输入 add Buy bread,看看是否显示 Saved note 3.。再输入 done 1,看看是否显示 Done: Buy milk。
亲手试试
import { existsSync } from 'node:fs';
import { readFile, writeFile } from 'node:fs/promises';
const file = 'notes.json';
// readFile 和 writeFile 现在会返回 Promise。用 await 等待它们各自完成。
const load = async () => {
if (!existsSync(file)) {
return [];
}
try {
return JSON.parse(readFile(file, 'utf8'));
} catch (err) {
console.error(`notes.json is damaged: ${err.message}`);
process.exit(1);
}
};
const store = {
notes: load(),
async save() {
writeFile(file, JSON.stringify(this.notes, null, 2));
},
async add(text) {
this.notes.push(text);
this.save();
return this.notes.length;
},
async remove(n) {
const [text] = this.notes.splice(n - 1, 1);
this.save();
return text;
},
};
export default store;
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
Node.js 基础中的所有课
自己练习: Express 在线编辑器