JavaScript異步通信三種玩法實例代碼
JavaScript 異步通信實例
你有沒有過這樣的經歷:去咖啡店點單,店員說"需要等5分鐘"。如果站在柜臺前一動不動地等(同步),這5分鐘啥也干不了;但如果先去旁邊買份報紙,等咖啡好了店員喊你(異步),這就高效多了。
JavaScript 里的"異步通信",本質上就是這種"不等結果先干活"的機制。
為什么 JavaScript 需要異步?
先搞懂一個前提:JavaScript 是單線程的。就像一個只有一個廚師的廚房,同一時間只能做一件事。
如果遇到"耗時操作"(比如從服務器拿數據、讀文件),如果讓線程一直等著(同步),整個程序就會"卡住"——頁面點不動、按鈕沒反應,用戶體驗會爛到家。
所以,異步就是讓 JavaScript 能在等結果的時候,先去處理其他任務的"小聰明"。
異步通信的三種玩法(從簡單到高級)
咱們從最原始的方法開始,一步步升級,每個方法都配可執(zhí)行的代碼,你可以直接復制到瀏覽器控制臺跑一跑。(注意,代碼運行結果的順序非常重要!)
1. 回調函數:最早的"留個聯(lián)系方式"
回調函數是最基礎的異步處理方式。就像點咖啡時告訴店員"做好了打我電話12345",這個"12345"就是回調函數。
示例1:用定時器模擬異步操作
// 模擬一個"煮咖啡"的異步操作(需要2秒)
function makeCoffee(callback) {
console.log("開始煮咖啡...");
// 2秒后執(zhí)行回調函數(通知咖啡好了)
setTimeout(() => {
const coffee = "熱拿鐵";
callback(coffee); // 調用回調,把結果傳過去
}, 2000);
}
// 點咖啡時,留個"回調聯(lián)系方式"
makeCoffee((coffee) => {
console.log(`咖啡好了:${coffee},開始喝!`);
});
// 注意:這行代碼會先執(zhí)行(不等咖啡煮好)
console.log("等咖啡的時候,先刷會兒手機...");
運行結果(順序很重要):
開始煮咖啡...
等咖啡的時候,先刷會兒手機...
// 2秒后...
咖啡好了:熱拿鐵,開始喝!

問題:回調地獄
如果多個異步操作要按順序執(zhí)行(比如先煮咖啡,再烤面包,再煎蛋),回調會嵌套成"地獄":
// 回調地獄示例(別這么寫!)
makeCoffee((coffee) => {
console.log(`喝了${coffee}`);
makeBread((bread) => {
console.log(`吃了${bread}`);
makeEgg((egg) => {
console.log(`吃了${egg},早餐完成!`);
});
});
});
嵌套越多,代碼越難維護,就像剝洋蔥一樣讓人頭疼。
2. Promise:給異步操作"立個軍令狀"
Promise 是 ES6 推出的解決方案,它像一個"軍令狀"——承諾"我會完成任務,結果要么成功要么失敗"。用 .then() 處理成功,.catch() 處理失敗,解決了回調地獄的嵌套問題。
示例2:用 Promise 改寫煮咖啡
// 用 Promise 包裝異步操作
function makeCoffee() {
console.log("開始煮咖啡...");
// 返回一個 Promise "軍令狀"
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = true; // 模擬是否成功
if (success) {
resolve("熱拿鐵"); // 成功:兌現承諾
} else {
reject("咖啡機壞了!"); // 失?。壕芙^承諾
}
}, 2000);
});
}
// 用 .then() 接結果,.catch() 處理錯誤
makeCoffee()
.then((coffee) => {
console.log(`咖啡好了:${coffee},開始喝!`);
// 可以繼續(xù)返回新的 Promise,實現鏈式調用
return "喝完咖啡,準備烤面包";
})
.then((msg) => {
console.log(msg);
})
.catch((error) => {
console.log("出錯了:", error);
});
console.log("等咖啡的時候,先刷會兒手機...");
運行結果和之前一樣,但代碼是"平著寫"的,不是嵌套的!這就是 Promise 解決回調地獄的核心:鏈式調用。

3. async/await:讓異步代碼看起來像同步
ES2017 推出的 async/await 是 Promise 的"語法糖",能讓異步代碼寫起來和同步代碼幾乎一樣,更符合人類的思維習慣。
示例3:用 async/await 簡化代碼
// 還是用上面的 makeCoffee(返回 Promise)
function makeCoffee() {
console.log("開始煮咖啡...");
return new Promise((resolve) => {
setTimeout(() => resolve("熱拿鐵"), 2000);
});
}
// 再加一個烤面包的異步函數
function makeBread() {
console.log("開始烤面包...");
return new Promise((resolve) => {
setTimeout(() => resolve("全麥面包"), 1500);
});
}
// 用 async 聲明異步函數,內部可以用 await
async function makeBreakfast() {
console.log("開始做早餐...");
// 等咖啡做好(await 會"暫停"到 Promise 完成)
const coffee = await makeCoffee();
console.log(`咖啡好了:${coffee}`);
// 再等面包烤好(按順序執(zhí)行,不嵌套)
const bread = await makeBread();
console.log(`面包好了:${bread}`);
return "早餐完成!";
}
// 調用異步函數(返回 Promise)
makeBreakfast().then((result) => {
console.log(result);
});
console.log("主線程:我先去干別的了...");
運行結果:
開始做早餐...
主線程:我先去干別的了...
開始煮咖啡...
// 2秒后...
咖啡好了:熱拿鐵
開始烤面包...
// 再1.5秒后...
面包好了:全麥面包
早餐完成!

是不是像同步代碼一樣直觀?但注意:await 只能在 async 函數里用,而且它不會阻塞主線程(其他代碼該跑還是跑)。
實戰(zhàn):用異步通信請求網絡數據
實際開發(fā)中,最常見的異步通信就是"從服務器拿數據"。咱們用 fetch API(返回 Promise)來演示:
// 用 async/await 請求網絡數據
async function queryGoodsData() {
try {
console.log("開始請求");
// 1. 發(fā)請求(await 等響應)
const response = await fetch("https://suggest.taobao.com/sug?code=utf-8&q=%E5%8D%AB%E8%A1%A3");
const data = await response.json();
// 2. 顯示結果
console.log("請求完成,結果數據:", data );
} catch (error) {
// 處理錯誤(比如網絡問題)
console.log("請求失敗:", error);
}
}
// 調用函數
queryGoodsData();
console.log("正在請求數據,稍等...");
先試用瀏覽器訪問 https://suggest.taobao.com/sug(為了解決跨域問題),然后啟用控制臺,將上述代碼直接復制到控制臺,會看到先輸出"正在請求數據",然后過一會兒顯示獲取到的商品信息。

總結:三種方式怎么選?
- 回調函數:適合極簡單的場景(比如單個定時器),但多步異步會變亂。
- Promise:解決了回調地獄,支持鏈式調用,適合復雜異步流程。
- async/await:Promise 的簡化寫法,代碼最易讀,優(yōu)先推薦使用。
記住核心:異步通信就是讓 JavaScript"不等結果先干活",避免程序卡住。就像生活中"多線程"處理任務一樣,高效又不耽誤事。
現在,你能不能用自己的話講講什么是異步通信了?如果能,說明你真的懂了~
到此這篇關于JavaScript異步通信三種玩法的文章就介紹到這了,更多相關JS異步通信內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
使用springboot+druid雙數據源動態(tài)配置操作
這篇文章主要介紹了使用springboot+druid雙數據源動態(tài)配置的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
springboot實現在工具類(util)中調用注入service層方法
這篇文章主要介紹了springboot實現在工具類(util)中調用注入service層方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06
Java SpringBoot安全框架整合Spring Security詳解
這篇文章主要介紹了Spring Boot整合Spring Security的示例代碼,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2021-09-09
解決MyEclipse10.7部署報錯拋空指針異常問題的方法
這篇文章主要介紹了解決MyEclipse10.7部署報錯拋空指針異常問題的方法,需要的朋友可以參考下2015-12-12

