简介:解析async/await核心原理,揭秘其基于Promise的底层工作机制:从async函数返回值特性、await执行流程,到事件循环协同原理,配合代码示例与编译转换逻辑,助你掌握JavaScript异步语法本质,写出高效可维护的异步代码
在 JavaScript 的异步编程领域,async/await 语法无疑是一次革命性的突破。它让异步代码的编写和阅读体验无限接近同步代码,极大地提升了开发效率和代码可维护性。本文将深入探讨 async/await 的底层原理和工作机制。
在理解 async/await 之前,我们需要回顾 JavaScript 异步编程的发展历程:
fs.readFile('file1.txt', 'utf8', (err1, data1) => {
if (err1) throw err1;
fs.readFile('file2.txt', 'utf8', (err2, data2) => {
if (err2) throw err2;
console.log(data1 + data2);
});
});
这种"回调地狱"导致代码可读性差、难以维护。
ES6 引入的 Promise 解决了部分问题:
function readFile(filename) {
return new Promise((resolve, reject) => {
fs.readFile(filename, 'utf8', (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
}
readFile('file1.txt')
.then(data1 => {
return readFile('file2.txt').then(data2 => data1 + data2);
})
.then(console.log)
.catch(console.error);
虽然改善了可读性,但嵌套的 .then() 仍然不够优雅。
async/await 是 ES2017 引入的语法糖,它建立在 Promise 之上,提供了更直观的异步编程方式:
async function readFiles() {
try {
const data1 = await readFile('file1.txt');
const data2 = await readFile('file2.txt');
console.log(data1 + data2);
} catch (err) {
console.error(err);
}
}
async 函数实际上返回一个 Promise 对象:
async function foo() {
return 42;
}
// 等价于
function foo() {
return Promise.resolve(42);
}
如果函数抛出异常,则返回被拒绝的 Promise:
async function bar() {
throw new Error('Oops!');
}
// 等价于
function bar() {
return Promise.reject(new Error('Oops!'));
}
await 表达式会暂停 async 函数的执行,等待 Promise 完成:
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}
其执行过程可以分解为:
async/await 的执行与 JavaScript 的事件循环和微任务队列密切相关:
async function test() {
console.log('Start');
await Promise.resolve(); // 暂停执行
console.log('End'); // 恢复执行
}
test();
console.log('Outside');
输出结果如下:
Start
Outside
End
这是因为:
虽然 await 看起来是顺序执行的,但我们可以通过将多个 Promise 组合来并行执行:
async function parallel() {
const [data1, data2] = await Promise.all([
fetch('https://api.example.com/data1'),
fetch('https://api.example.com/data2')
]);
const result1 = await data1.json();
const result2 = await data2.json();
return { result1, result2 };
}
从编译器角度来看,async/await 实际上被转换为生成器函数和 Promise 的组合。例如:
async function foo() {
const a = await bar();
const b = await baz(a);
return b;
}
大致会被转换为:
function foo() {
return spawn(function*() {
const a = yield bar();
const b = yield baz(a);
return b;
});
}
// spawn 函数的简化实现
function spawn(genF) {
return new Promise((resolve, reject) => {
const gen = genF();
function step(nextF) {
let next;
try {
next = nextF();
} catch (e) {
return reject(e);
}
if (next.done) {
return resolve(next.value);
}
Promise.resolve(next.value).then(
x => step(() => gen.next(x)),
e => step(() => gen.throw(e))
);
}
step(() => gen.next(undefined));
});
}
async/await 并不是 JavaScript 引擎的新特性,而是基于 Promise 的语法糖。它的核心工作原理是:
这种设计既保持了 JavaScript 的单线程特性,又提供了直观的异步编程体验,是现代 JavaScript 开发中不可或缺的工具。
有遗漏或者不对的可以在我的公众号留言哦