教程(十四):async/await)
一、什么是 async/await在 Node.js 中async/await 是一種處理異步操作的語(yǔ)法糖。async/await 基于 Promise但讓異步代碼看起來(lái)更像同步代碼極大地提高了代碼的可讀性和可維護(hù)性。async關(guān)鍵字用于聲明一個(gè)函數(shù)是異步的而await關(guān)鍵字用于等待一個(gè) Promise 的解決resolve或拒絕reject。使用 async/await 可以避免回調(diào)地獄callback hell并使錯(cuò)誤處理更加直觀。二、基本語(yǔ)法async 函數(shù)任何函數(shù)都可以通過(guò)添加async關(guān)鍵字變成異步函數(shù)async function myFunction() { return Hello World; } // 等價(jià)于 function myFunction() { return Promise.resolve(Hello World); }async函數(shù)總是返回一個(gè) Promise。如果返回值不是 Promise它會(huì)被自動(dòng)包裝成 Promise。await 表達(dá)式await只能在async函數(shù)內(nèi)部使用它會(huì)暫停函數(shù)的執(zhí)行等待 Promise 解決然后繼續(xù)執(zhí)行并返回結(jié)果async function fetchData() { const response await fetch(https://api.example.com/data); const data await response.json(); return data; }三、錯(cuò)誤處理try/catch 方式處理 async/await 錯(cuò)誤最常用的方法是使用try/catchasync function getUser() { try { const response await fetch(https://api.example.com/user); const user await response.json(); return user; } catch (error) { console.error(Error fetching user:, error); throw error; // 可以選擇重新拋出錯(cuò)誤 } }直接處理 Promise你也可以直接處理返回的 PromisegetUser() .then(user console.log(user)) .catch(error console.error(error));四、實(shí)際應(yīng)用示例并行執(zhí)行多個(gè)異步操作使用Promise.all結(jié)合 async/await 可以并行執(zhí)行多個(gè)異步操作async function fetchMultipleUrls(urls) { try { const requests urls.map(url fetch(url)); const responses await Promise.all(requests); const data await Promise.all(responses.map(r r.json())); return data; } catch (error) { console.error(Error fetching data:, error); throw error; } } // 使用 const data await fetchMultipleUrls([ https://api.example.com/users, https://api.example.com/posts ]);順序執(zhí)行 vs 并行執(zhí)行順序執(zhí)行較慢適合有依賴(lài)關(guān)系的操作async function sequentialTasks() { const user await getUser(); // 等待完成 const posts await getPosts(); // 再執(zhí)行下一個(gè) return { user, posts }; }并行執(zhí)行較快適合獨(dú)立的操作async function parallelTasks() { const userPromise getUser(); const postsPromise getPosts(); const [user, posts] await Promise.all([userPromise, postsPromise]); return { user, posts }; }數(shù)據(jù)庫(kù)操作示例async function getUserAndPosts(userId) { try { const user await User.findById(userId); const posts await Post.find({ userId }); return { user, posts }; } catch (error) { console.error(Database error:, error); throw error; } }文件操作示例const fs require(fs).promises; async function readFiles() { try { const data1 await fs.readFile(file1.txt, utf8); const data2 await fs.readFile(file2.txt, utf8); console.log(Data:, data1, data2); } catch (err) { console.error(讀取文件出錯(cuò):, err); } }五、最佳實(shí)踐實(shí)踐說(shuō)明總是處理錯(cuò)誤不要忽略 await 可能拋出的錯(cuò)誤使用 try/catch 或.catch()處理避免不必要的 await如果不需要等待結(jié)果可以直接返回 Promise合理使用并行多個(gè)獨(dú)立的異步操作應(yīng)該并行執(zhí)行使用Promise.all保持代碼清晰避免過(guò)深的 async/await 嵌套必要時(shí)提取函數(shù)注意性能影響每個(gè) await 都會(huì)暫停函數(shù)執(zhí)行在循環(huán)中要特別注意六、常見(jiàn)問(wèn)題async/await 與 Promise 的關(guān)系async/await 是建立在 Promise 之上的語(yǔ)法糖。任何async函數(shù)都返回 Promise任何await后面都可以接 Promise。// async/await 和 Promise 可以混用 async function processUser() { const user await getUser(); const posts await getPosts(user.id); return posts; // 等價(jià)于 return Promise.resolve(posts) } // 返回的異步函數(shù)本身就是 Promise processUser().then(posts console.log(posts));為什么我的 async 函數(shù)返回 undefined這可能是因?yàn)橥浽?await 前使用return或者在 Promise 解決前函數(shù)就退出了。// 錯(cuò)誤示例沒(méi)有 return返回 undefined async function getData() { await fetch(url); // 沒(méi)有 return } // 正確示例使用 return async function getData() { return await fetch(url); } // 或者直接返回 Promise async function getData() { return fetch(url); // 自動(dòng)包裝為 Promise }可以在頂層使用 await 嗎在ES 模塊中文件以.mjs結(jié)尾或package.json中type: module可以直接在頂層使用await。在 CommonJS 模塊中需要包裹在 async 函數(shù)中。// ES 模塊中可以直接使用頂層 await const data await fetchData(); console.log(data); // CommonJS 模塊中需要包裹 (async () { const data await fetchData(); console.log(data); })();七、本章小結(jié)知識(shí)點(diǎn)說(shuō)明async聲明異步函數(shù)返回 Promiseawait等待 Promise 解決只能在 async 函數(shù)中使用錯(cuò)誤處理使用try/catch或.catch()處理異步錯(cuò)誤并行執(zhí)行使用Promise.all同時(shí)執(zhí)行多個(gè)獨(dú)立的異步操作順序執(zhí)行使用await依次執(zhí)行有依賴(lài)關(guān)系的異步操作頂層 awaitES 模塊中支持CommonJS 中需包裹在 async 函數(shù)中提示async/await 是現(xiàn)代 Node.js 異步編程的推薦方式。它讓異步代碼看起來(lái)像同步代碼大大提高了代碼的可讀性和可維護(hù)性。但要記住await會(huì)暫停函數(shù)執(zhí)行在循環(huán)中使用時(shí)要考慮性能影響無(wú)關(guān)的操作應(yīng)該用Promise.all并行執(zhí)行。