javascript是單線程編程,意思就是javascript引擎一次只能執(zhí)行一個語句宗兼。這樣在出現(xiàn)長時間的請求的話躏鱼,會阻塞主線程,為了不阻塞主線程殷绍,出現(xiàn)了javascript異步的概念染苛。
javascript 同步異步理解:
設想這樣的情景,你現(xiàn)在路過一個炸雞店主到,聞著特別香茶行,你實在抵擋不住炸雞的誘惑,你就走上前登钥,買了一份炸雞畔师。
同步的情況是:你點了一份炸雞,然后你站到跟前等著啥也不干牧牢,炸雞好了之后看锉,你付錢給老板。
異步的情況是:你點了一份炸雞塔鳍,然后老板給你一張?zhí)柎a單伯铣,你把錢付了,玩著手機等轮纫,炸雞好了之后懂傀,老板再叫你。
同步代碼:
const makeChicken = () => {
console.log('炸雞好了')
}
console.log('我要吃炸雞')
makeChicken()
console.log('給你炸雞錢')
console.log('玩手機')
執(zhí)行結果:
我要吃炸雞
炸雞好了
給你炸雞錢
玩手機
異步代碼:
const makeChicken = () => {
setTimeout(() => {
console.log('炸雞好了')
}, 2000)
}
console.log('我要吃炸雞')
makeChicken()
console.log('給你炸雞錢')
console.log('玩手機')
執(zhí)行結果:
我要吃炸雞
給你炸雞錢
玩手機
炸雞好了
異步實現(xiàn)邏輯:
事件循環(huán)蜡感、web APIs 和消息隊列不是JavaScript引擎的一部分,它們是瀏覽器端的JavaScript運行環(huán)境或者Nodejs端的JavaScript運行環(huán)境的一部分恃泪。在Nodejs中郑兴,web APIs被C/C++ APIs替代。
當上面的代碼加載在瀏覽器中贝乎,console.log('我要吃炸雞')情连,被推到棧中然后當結束時從棧中被移除。然后览效,makeChicken()觸發(fā)却舀,然后它被推到了棧的頂部虫几。
接下來setTimeOut( )函數(shù)被調用,所以它被推到了棧頂挽拔。setTimeOut( )有兩個參數(shù):一是回調辆脸,二是毫秒數(shù)盏檐。
這個setTimeOut( )方法在web APIs環(huán)境中開始了一個2秒的計時器事镣。此時,setTimeOut( )執(zhí)行完畢并被移出棧掰曾。之后术裸,console.log('給你炸雞錢')倘是,被推到棧里,執(zhí)行完后被移除袭艺。
同時搀崭,計時器到期了,現(xiàn)在這個回調被推到了消息隊列猾编。但是這回調不會被立即執(zhí)行瘤睹,這里就是事件循環(huán)插手的地方。
事件循環(huán)的作用是查看調用棧并確定調用棧是否為空袍镀。 如果調用棧為空默蚌,它會查看消息隊列以查看是否有任何掛起的回調等待執(zhí)行。
在上面的例子中苇羡,消息隊列中有一個回調绸吸,并且此時調用棧已經(jīng)空了。 因此设江,事件循環(huán)將回調推到棧頂部锦茁。
之后, console.log('炸雞好了')被推到棧頂部叉存,執(zhí)行完后從堆棧中彈出码俩。 此時,回調已執(zhí)行完畢歼捏,因此被從棧中移除稿存,程序最終完成。
異步的幾種實現(xiàn):
1)回調函數(shù):
意思就是等到炸雞好了再叫你瞳秽。
function getYourFood() {
console.log('給你炸雞')
}
function getChicken(callback) {
console.log('準備制作炸雞')
setTimeout(() => {
console.log('炸雞制作完成')
callback()
}, 2000)
}
getChicken(getYourFood)
執(zhí)行結果:
我要炸雞
準備制作炸雞
炸雞制作完成
給你炸雞
2)promise
使我們可以主動的去執(zhí)行后面的動作瓣履,而不是把回調函數(shù)給一個方法等在這個方法內部調用。
function makeChicken() {
return new Promise(((resolve) => {
console.log('準備制作炸雞')
setTimeout(() => {
resolve('炸雞成功')
console.log('炸雞制作完成')
}, 2000)
console.log('炸雞制作中')
}))
}
function getYourFood() {
return new Promise(((resolve) => {
resolve('炸雞好了')
}))
}
console.log('我要炸雞')
makeChicken().then(() => {
getYourFood().then((seccess) => {
console.log(seccess)
})
})
執(zhí)行結果:
我要炸雞
準備制作炸雞
炸雞制作中
炸雞制作完成
炸雞好了
3)async await
使異步代碼看起來就是同步代碼练俐。我們添加一個關鍵字async讓引擎知道哪個函數(shù)觸發(fā)是異步的并且會返回一個promise袖迎,讓我們使用await。
function makeChicken() {
return new Promise(((resolve) => {
console.log('準備制作炸雞')
setTimeout(() => {
resolve('炸雞成功')
console.log('炸雞制作完成')
}, 2000)
console.log('炸雞制作中')
}))
}
function getYourFood() {
return new Promise(((resolve) => {
resolve('炸雞好了')
}))
}
async function OrderChicken() {
await makeChicken()
const result = await getYourFood()
console.log(result)
}
console.log('我要炸雞')
OrderChicken()
運行結果:
我要炸雞
準備制作炸雞
炸雞制作中
炸雞制作完成
炸雞好了
我覺得下面鏈接的有關異步的講解特別好。
參考鏈接:
[譯]理解異步JavaScript-事件循環(huán)https://mbd.baidu.com/newspage/data/landingshare?pageType=1&isBdboxFrom=1&context=%7B%22nid%22%3A%22news_9071904341435333508%22%2C%22sourceFrom%22%3A%22bjh%22%7D
[翻譯]JavaScript異步進化史:Callbacks,Promises,Async/Await 上
https://mbd.baidu.com/newspage/data/landingshare?context=%7B%22nid%22%3A%22news_8754335365643315921%22%2C%22sourceFrom%22%3A%22bjh%22%7D&type=news
[翻譯]JavaScript異步進化史之下篇
https://mbd.baidu.com/newspage/data/landingshare?context=%7B%22nid%22%3A%22news_9356479249406614478%22%2C%22sourceFrom%22%3A%22bjh%22%7D&type=news