JavaScript通過(guò)外賣(mài)訂單講解異步編程
同步vs異步-點(diǎn)外賣(mài)的智慧
想象一下你要準(zhǔn)備一頓晚餐:
同步方式(不推薦):
- 走進(jìn)廚房開(kāi)始煮飯
- 站在灶臺(tái)前盯著鍋,什么都不做,直到飯煮好(20分鐘)
- 飯好了才開(kāi)始洗菜切菜
- 再花30分鐘炒菜
- 總共耗時(shí):50分鐘
異步方式(聰明做法):
- 開(kāi)始煮飯(設(shè)置定時(shí)器)
- 在飯煮的同時(shí)洗菜切菜
- 飯好了的提示音響起時(shí)處理飯
- 繼續(xù)炒菜
- 總共耗時(shí):35分鐘
JavaScript的異步編程就像是那個(gè)聰明的廚師,讓多個(gè)任務(wù)可以同時(shí)進(jìn)行!
回調(diào)函數(shù)-JavaScript的電話(huà)通知
最早的異步處理方式是回調(diào)函數(shù):
// 點(diǎn)外賣(mài)的比喻:下單后留下電話(huà)號(hào)碼,外賣(mài)到了打電話(huà)通知你
orderFood('pizza', function(pizza) {
console.log(`我的${pizza}到了!可以開(kāi)動(dòng)了!`);
});
console.log('在等外賣(mài)的時(shí)候,我可以繼續(xù)刷劇...');但問(wèn)題來(lái)了——如果你需要按順序做多件事呢?
// “回調(diào)地獄”出現(xiàn)了!
orderFood('pizza', function(pizza) {
getDrink('cola', function(cola) {
buyNapkins(function(napkins) {
console.log(`準(zhǔn)備好享用${pizza}+${cola}了,還有${napkins}張餐巾紙`);
// 更多嵌套...
});
});
});這就像是:等外賣(mài)→外賣(mài)到了買(mǎi)飲料→飲料到了買(mǎi)紙巾……效率太低了!
Promise-外賣(mài)訂單追蹤系統(tǒng)
ES6帶來(lái)了Promise,就像外賣(mài)平臺(tái)的應(yīng)用,可以追蹤訂單狀態(tài):
// 創(chuàng)建一個(gè)Promise就像下一個(gè)外賣(mài)訂單
const foodOrder = new Promise((resolve, reject) => {
// 模擬烹飪時(shí)間
setTimeout(() => {
const success = Math.random() > 0.1; // 90%的成功率
success ? resolve('香噴噴的披薩') : reject('抱歉,烤箱壞了');
}, 2000);
});
// 追蹤訂單狀態(tài)
foodOrder
.then(food => {
console.log(`?? ${food}送達(dá)!`);
return '吃完了,該收拾了'; // 可以繼續(xù)返回新的Promise
})
.then(message => {
console.log(message);
})
.catch(error => {
console.log(`?? ${error}`);
})
.finally(() => {
console.log('這次訂餐體驗(yàn)結(jié)束了');
});
console.log('訂單已下,我可以繼續(xù)工作...');async/await-像寫(xiě)同步代碼一樣寫(xiě)異步
ES7的async/await讓異步代碼看起來(lái)像同步代碼一樣直觀(guān):
async function enjoyDinner() {
try {
console.log('開(kāi)始準(zhǔn)備晚餐...');
// 看起來(lái)是同步的,但實(shí)際上是異步的!
const pizza = await orderPizza();
console.log(`${pizza}準(zhǔn)備好了`);
const drink = await orderDrink();
console.log(`${drink}也到了`);
// 這兩個(gè)可以同時(shí)進(jìn)行!
const [napkins, movie] = await Promise.all([
buyNapkins(),
loadMovie()
]);
console.log(`完美!有${pizza}、${drink}、${napkins}和電影${movie}`);
} catch (error) {
console.log(`晚餐計(jì)劃失敗:${error}`);
}
}
// 模擬的異步函數(shù)
function orderPizza() {
return new Promise(resolve => {
setTimeout(() => resolve('??意大利香腸披薩'), 2000);
});
}事件循環(huán)-JavaScript的時(shí)間管理大師
JavaScript是單線(xiàn)程的,但它有一個(gè)神奇的事件循環(huán)機(jī)制:
console.log('1. 開(kāi)始做飯');
setTimeout(() => {
console.log('4. 定時(shí)器到時(shí)間了(飯煮好了)');
}, 0);
Promise.resolve()
.then(() => {
console.log('3. Promise微任務(wù)(嘗一下味道)');
});
console.log('2. 繼續(xù)切菜');
// 輸出順序:
// 1. 開(kāi)始做飯
// 2. 繼續(xù)切菜
// 3. Promise微任務(wù)(嘗一下味道)
// 4. 定時(shí)器到時(shí)間了(飯煮好了)簡(jiǎn)單來(lái)說(shuō):
- 同步任務(wù)立即執(zhí)行
- 微任務(wù)(Promise)在當(dāng)前任務(wù)結(jié)束后立即執(zhí)行
- 宏任務(wù)(setTimeout)在微任務(wù)之后執(zhí)行
實(shí)際應(yīng)用-有趣的例子
// 模擬一個(gè)加載進(jìn)度指示器
async function loadContentWithProgress() {
const tasks = [
'加載用戶(hù)數(shù)據(jù)',
'獲取朋友圈',
'下載圖片',
'初始化聊天'
];
for (let i = 0; i < tasks.length; i++) {
// 模擬每個(gè)任務(wù)的耗時(shí)
await new Promise(resolve =>
setTimeout(resolve, Math.random() * 1000 + 500)
);
const progress = ((i + 1) / tasks.length) * 100;
console.log(`?? ${tasks[i]}... 進(jìn)度:${progress.toFixed(0)}%`);
}
console.log('? 所有內(nèi)容加載完成!');
}
// 使用Promise.race實(shí)現(xiàn)超時(shí)控制
function fetchWithTimeout(url, timeout = 3000) {
const fetchPromise = fetch(url);
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('請(qǐng)求超時(shí)')), timeout);
});
return Promise.race([fetchPromise, timeoutPromise]);
}異步編程的黃金法則
- 避免阻塞:長(zhǎng)時(shí)間運(yùn)行的任務(wù)要異步化
- 錯(cuò)誤處理:不要忘記.catch()或try-catch
- 適度使用:不是所有東西都需要異步
- 保持簡(jiǎn)單:能用async/await就不用復(fù)雜的Promise鏈
總結(jié)
JavaScript的異步編程就像生活中的多任務(wù)處理:我們不會(huì)等水燒開(kāi)時(shí)傻站著,而是同時(shí)準(zhǔn)備其他食材。從回調(diào)函數(shù)到Promise再到async/await,JavaScript為我們提供了越來(lái)越優(yōu)雅的方式來(lái)處理異步操作。
記住,好的異步代碼就像一場(chǎng)精心編排的交響樂(lè)——每個(gè)部分在正確的時(shí)間奏響,整體和諧而不混亂。
希望這篇文章讓你對(duì)JavaScript異步編程有了更直觀(guān)的理解!現(xiàn)在,試著把你的下一個(gè)耗時(shí)操作改成異步吧,讓你的應(yīng)用變得更加流暢!
小挑戰(zhàn):你能用async/await寫(xiě)一個(gè)模擬“同時(shí)煮面、煎蛋、烤面包”的早餐制作程序嗎?
以上就是JavaScript通過(guò)外賣(mài)訂單講解異步編程的詳細(xì)內(nèi)容,更多關(guān)于JavaScript異步編程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
一步步教你用js簡(jiǎn)單實(shí)現(xiàn)新年倒計(jì)時(shí)
一轉(zhuǎn)眼已經(jīng)臘月了,相信小伙伴們一定想知道我們距離2023新年還有多少天,下面這篇文章主要給大家介紹了關(guān)于如何一步步教你用js簡(jiǎn)單實(shí)現(xiàn)新年倒計(jì)時(shí)的相關(guān)資料,需要的朋友可以參考下2022-12-12
詳解JavaScript中new操作符的解析和實(shí)現(xiàn)
這篇文章主要介紹了JavaScript中new操作符的解析和實(shí)現(xiàn),幫助大家更好的理解和學(xué)習(xí)JavaScript,感興趣的朋友可以了解下2020-09-09
BootStrap實(shí)現(xiàn)手機(jī)端輪播圖左右滑動(dòng)事件
用bootstrap做出的項(xiàng)目輪播圖在手機(jī)端不能滑動(dòng),為此找了好多插件、框架。但是都不能和bootstrap良好的結(jié)合。經(jīng)過(guò)一番折騰終于找到了解決方法,下面小編通過(guò)本文給大家簡(jiǎn)單介紹下2016-10-10
JS遍歷JSON數(shù)組及獲取JSON數(shù)組長(zhǎng)度操作示例【測(cè)試可用】
這篇文章主要介紹了JS遍歷JSON數(shù)組及獲取JSON數(shù)組長(zhǎng)度操作,涉及javascript簡(jiǎn)單json數(shù)組遍歷與運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2018-12-12
利用純js + transition動(dòng)畫(huà)實(shí)現(xiàn)移動(dòng)端web輪播圖詳解
這篇文章主要給大家介紹了利用純js + transition動(dòng)畫(huà)實(shí)現(xiàn)移動(dòng)端web輪播圖的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-09-09
Javascript 一些需要注意的細(xì)節(jié)(必看篇)
下面小編就為大家?guī)?lái)一篇Javascript 一些需要注意的細(xì)節(jié)(必看篇)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07

