async/await 可能會(huì)產(chǎn)生誤導(dǎo)!十厢!
在我沒(méi)研究一下之前等太,本人也是一臉懵逼,什么同步蛮放,異步缩抡,串行,并行包颁。await 不就是寫異步代碼的嗎瞻想?
//噢不,我簡(jiǎn)直是SB娩嚼,我怎么會(huì)說(shuō)出 await 不就是寫異步代碼的嗎蘑险?這樣的話?
一些文章將 async/wait 與 Promise 進(jìn)行了比較岳悟,并聲稱它是 JavaScript 下一代異步編程風(fēng)格佃迄,事實(shí)上它只不過(guò)是一種語(yǔ)法糖,不會(huì)完全改變我們的編程風(fēng)格竿音。
從本質(zhì)上說(shuō)和屎,async 函數(shù)仍然是 promise。在正確使用 async 函數(shù)之前春瞬,你必須先了解 promise柴信,更糟糕的是,大多數(shù)時(shí)候你需要在使用 promises 的同時(shí)使用 async 函數(shù)宽气。
算了随常,要理解這些,先從頭復(fù)習(xí)一下吧
第一部分????:
在當(dāng)年寫ajax的時(shí)候,多個(gè)請(qǐng)求的寫法
假設(shè) setTimeout 模擬請(qǐng)求,a和b模擬請(qǐng)求返回的數(shù)據(jù)并打印,一個(gè)請(qǐng)求假設(shè)4s
function b(){
let a = 0 ;
setTimeout(()=>{a=4;console.log(a)},4000)
let b = 0 ;
setTimeout(()=>{b=5;console.log(b)},4000)
}
寫完覺(jué)得自己特牛B萄涯,兩個(gè)請(qǐng)求并行(一起執(zhí)行)绪氛,只用了4.097s
如果兩個(gè)請(qǐng)求的數(shù)據(jù)之間有依賴性,也就是b請(qǐng)求需要a請(qǐng)求返回的數(shù)據(jù)
function b(){
let a = 0 ;
let b = 0 ;
setTimeout(()=>{a=4;console.log(a)
setTimeout(()=>{b=5;console.log(b);},4000)}
,4000)
}
噢不,居然用了8.097 這就是
串行
涝影。如果這個(gè)時(shí)候我寫了回調(diào)函數(shù)進(jìn)行枣察。單個(gè)請(qǐng)求還無(wú)所謂,多個(gè)請(qǐng)求或者多次操作就會(huì)不優(yōu)雅了.
第二部分????
無(wú)所謂,promise會(huì)出手
隨便去網(wǎng)上搜索一下promise的作用就知道promise就是解決回調(diào)地獄的
(以為多高大上呢序目,不就是優(yōu)雅的問(wèn)題嗎臂痕?)
function c(){
new Promise((res,rej)=>{
setTimeout(() => {
res(1)
}, 2000);
}).then(v=>console.log(v))
console.log(4);
new Promise((res,rej)=>{
setTimeout(() => {
res(3)
}, 2000);
}).then(v=>console.log(v))
console.log(2);
}
Promise的意思是聲明一個(gè)異步代碼去執(zhí)行,并承諾未來(lái)一段時(shí)間內(nèi)會(huì)有結(jié)果返回(resolve,reject)這個(gè)結(jié)果使用 then函數(shù)來(lái)接受并實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用
上邊的代碼也是并行
執(zhí)行了兩個(gè)promise猿涨。耗時(shí) 2.087s
何為異步代碼握童?其實(shí)你看到4和2先打印了,這其實(shí)就是異步代碼
的作用叛赚,在promise的同時(shí)js線程并不會(huì)阻塞
澡绩。
第三部分????
但是 promise 感覺(jué)仍然不夠優(yōu)雅,無(wú)所謂,async 會(huì)出手
async function a(){
console.log(new Date().getSeconds());
const a = new Promise((res,rej)=>{
setTimeout(()=>res('fffa'),4000)
})
const a1 = await a
console.log(a1);
console.log(new Date().getSeconds());
const b = new Promise((res,rej)=>{
setTimeout(()=>res('fffb'),4000)
})
const b1 = await b
console.log(b1);
console.log(new Date().getSeconds());
}
這里是重點(diǎn)了俺附,我們看到打印順序是按照同步代碼的結(jié)果來(lái)打印的肥卡,耗時(shí)8.098s
這就是 async/await 的作用。讓
異步
的代碼寫起來(lái)更像是同步的代碼
一樣(目前暫時(shí)是串行的)拋開(kāi)對(duì)async/await的認(rèn)識(shí)昙读,我們解讀這段代碼
1.分別寫了兩段異步代碼 Promise召调,他們的結(jié)果是 a,b 并且分別打印。
2.兩個(gè)異步代碼的數(shù)據(jù)沒(méi)有依賴性蛮浑。執(zhí)行耗時(shí)是8.098s是正確的。
3.前提是我們把他們看作是同步的代碼
4.程序在8秒起步只嚣,過(guò)了4秒在12秒時(shí)候打印fffa 沮稚,再過(guò)4秒就是16秒的時(shí)候打印fffb
但這其實(shí)也是很多人在使用 async/await
時(shí)可能會(huì)犯的錯(cuò)誤::
太過(guò)串行化!!!
盡管 await
可以使代碼看起來(lái)像是同步的,但實(shí)際它們?nèi)匀皇钱惒降牟嵛瑁仨毿⌒谋苊馓^(guò)串行化蕴掏。這會(huì)導(dǎo)致執(zhí)行時(shí)間是多一倍的(8s),實(shí)際應(yīng)該是4s左右
上述代碼在邏輯上看似正確的调鲸,然而盛杰,這不是完全正確的。
await a 會(huì)等待 fffa 結(jié)束并返回結(jié)果藐石。
然后 await b的部分才被調(diào)用即供。執(zhí)行的總時(shí)間用了8s!
注意于微,b部分的代碼 并不依賴于 a部分 的結(jié)果逗嫡,實(shí)際上它們可以并行
調(diào)用!然而株依,用了 await驱证,兩個(gè)調(diào)用變成串行的,總的執(zhí)行時(shí)間將比并行多一倍時(shí)間
下面是正確的方式:我們把 const a1 = await a 的執(zhí)行時(shí)機(jī)放到了 兩個(gè)promise 的后邊
async function a(){
console.log(new Date().getSeconds());
const a = new Promise((res,rej)=>{
setTimeout(()=>res('fffa'),4000)
})
console.log(new Date().getSeconds());
const b = new Promise((res,rej)=>{
setTimeout(()=>res('fffb'),4000)
})
const a1 = await a
const b1 = await b
console.log(a1);
console.log(b1);
console.log(new Date().getSeconds());
}
為什么恋腕?為什么調(diào)換了 await a 的順序就沒(méi)問(wèn)題了抹锄?
答????:
先拋出 await 的術(shù)語(yǔ)解釋:await
操作符用于等待一個(gè) [Promise
]兌現(xiàn)并獲取它兌現(xiàn)之后的值
但我個(gè)人用通俗的解釋:await 有點(diǎn)像 then()/catch(),用來(lái)接受promise返回的值。
這里 await a 的時(shí)候伙单,a是promise返回的值获高。后邊的代碼我們可以想象有點(diǎn)像被then()包裹起來(lái)了,貌似await不能很好的控制后邊的代碼哪些需要同步或異步
導(dǎo)致了
const a1 = await a
console.log(a1);
console.log(new Date().getSeconds());
const b = new Promise((res,rej)=>{
這段代碼 b部分的Promise 也會(huì)等待 await a 拿到結(jié)果再去執(zhí)行车份。就不小心串行
了
所以結(jié)果是 8s.
當(dāng)我調(diào)換了順序之后-->
const a1 = await a
const b1 = await b
console.log(a1);
console.log(b1);
這里的 兩個(gè)await 并不會(huì)妨礙到 它上邊兩個(gè)promise 的執(zhí)行谋减,就像是 第二部分
的promise代碼一樣,是并行
執(zhí)行的扫沼。不過(guò)這里有另一個(gè)細(xì)節(jié)!!
盡管 兩個(gè)await 不會(huì)妨礙到promise的并行執(zhí)行出爹,但是 此時(shí) await a 會(huì)等待 a返回結(jié)果,程序此時(shí)還沒(méi)走到 await b.
也就是說(shuō)
此時(shí)程序執(zhí)行不是卡在 await b缎除,而是卡在 await a,
當(dāng) fffa 被返回的時(shí)候严就,由于兩個(gè) promise 是并行執(zhí)行的!
fffa 被返回的同時(shí)器罐,await a 得到結(jié)果梢为,程序就立馬走到 await b,由于并行且時(shí)間差不大轰坊,剛好fffb也就被返回铸董,
所以 await a 和 await b 是幾乎同一時(shí)間結(jié)果被返回,但是實(shí)際開(kāi)發(fā)環(huán)境可能是 await a返回之后要等個(gè)時(shí)間 b才會(huì)被返回肴沫,
具體看服務(wù)器接口請(qǐng)求時(shí)間粟害。
然后 console.log(a1); console.log(b1); 被一起打印
這才是真正的 await 并行請(qǐng)求!
當(dāng)然也不是完全否定了 串行颤芬,假如有一個(gè)需求悲幅,b的請(qǐng)求數(shù)據(jù) 需要包含 a請(qǐng)求返回的數(shù)據(jù),那么 b 需要等待 a站蝠, 就可以用串行的寫法了
雖然有點(diǎn)啰嗦汰具,但是為了講清楚點(diǎn),我只能這么碼字菱魔,希望有人看得懂留荔,技術(shù)有限,歡迎噴我