async函数本质是Promise的语法糖,返回Promise对象;await仅在async函数内有效,暂停当前函数但不阻塞主线程;多请求需用Promise.all并发;错误必须用try/catch显式处理。
它只是 Promise 的封装层,底层仍依赖 Promise 状态流转。声明一个 async 函数,等价于返回一个自动 resolve 的 Promise:
async function foo() {
return 'done';
}
// 等价于
function foo() {
return Promise.resolve('done');
}
这意味着:即使函数体里没写 await,调用它仍会返回 Promise;你不能直接拿到返回值,必须用 .then() 或外层再套 await。
常见误操作:const res = foo() 拿到的是 Promise 对象,不是字符串 'done' —— 这是初学者最常卡住的地方。
await 不是全局关键字,它依赖 async 函数提供的执行上下文。在普通函数、事件回调、setTimeout 回调里直接写 await 会报错:SyntaxError: await is only valid in async functions。
async 函数中 await f
etch('/api')
document.addEventListener('click', () => { await getData(); }) 中直接 await
async,或改用 .then()
注意:箭头函数也能 async,但必须显式标注:const handler = async () => { await apiCall(); }。
这是关键理解点。await 暂停的是当前 async 函数的执行流(类似“让出控制权”),JS 引擎会继续处理其他任务(如渲染、其他事件),等 Promise settle 后再恢复该函数。
所以以下代码不会卡死页面:
async function loadAndRender() {
const data = await fetch('/data').then(r => r.json());
document.body.innerHTML = JSON.stringify(data);
}
但要注意顺序陷阱:
await 是串行的:后一个要等前一个完成才开始Promise.all([p1, p2]) 包裹,再 await 它await Promise.all([fetch('/a'), fetch('/b')]) 比两个单独 await 快得多await 遇到 rejected 的 Promise 会直接抛出异常,不加 try/catch 就会变成未捕获异常(unhandled rejection),可能触发 unhandledrejection 事件甚至崩溃。
不要这样写:
async function bad() {
const res = await fetch('/fail'); // 404 时这里就 throw
return res.json();
}
应该:
async function good() {
try {
const res = await fetch('/fail');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (err) {
console.error('API failed:', err);
return null;
}
}
容易被忽略的一点:被 catch 捕获的错误,**不是原始 Promise reject 的值本身**,而是它包装后的 Error 实例(尤其在 fetch 场景下,需手动检查 res.ok)。