這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

前言
async await 語法是 ES7出現的,是基于ES6的 promise和generator實作的
generator函式
在之前我專門講個generator的使用與原理實作,大家沒了解過的可以先看那個手寫generator核心原理,再也不怕面試官問我generator原理
這里就不再贅述generator,專門的文章講專門的內容,
await在等待什么
我們先看看下面這代碼,這是async await的最簡單使用,await后面回傳的是一個Promise物件:
async function getResult() {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
}
getResult()
但不知你有沒有想過一個問題,為什么會等到回傳的promise的物件的狀態為非pending的時候才會繼續往下執行,也就是resolve執行之后,才會繼續執行,就像下面的代碼一樣
async function getResult() {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
console.log(2);
}
getResult()

可以看到運行結果是先列印了1,再列印2了,也就是說明在回傳的promise物件沒執行resolve()前,就一直在await,等它執行,然后再執行下面的程式,那這個是怎么實作的呢?
原理實作
我們看一下下面的代碼,輸出順序是什么?
async function getResult() {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
})
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
getResult()
沒錯是 1,2,3.
那用generator函式專門來實作這個效果呢
我一開始這樣來實作:
function* getResult(params) {
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
const gen = getResult()
gen.next();
gen.next();
gen.next();
但是發現列印順序是 3,2,1.明顯不對,
這里的問題主要是三個 new Promise幾乎是同一時刻執行了,才會出現這種問題,所以需要等第一個promise執行完resolve之再執行下一個,所以要這么實作
function* getResult(params) {
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
const gen = getResult()
gen.next().value.then(() => {
gen.next().value.then(() => {
gen.next();
});
});

可以看到這樣就列印正常了,
特別 需要解釋下,gen.next().value 就是回傳的promise物件,不理解的可以看看文首介紹的那篇generator的 文章,手寫generator核心原理,再也不怕面試官問我generator原理
優化
但是呢,總不能有多少個await,就要自己寫多少個嵌套吧,所以還是需要封裝一個函式,顯然,遞回實作最簡單
function* getResult(params) {
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
const gen = getResult()
function co(g) {
g.next().value.then(()=>{
co(g)
})
}
co(gen)
再來看看列印結果

可以發現成功執行了,但是為什么報錯了?
這是因為generator方法會回傳四次,最后一次的value是undefined,
而實際上回傳第三次就表示已經回傳done,代表結束了,所以,我們需要判斷是否是已經done了,不再讓它繼續遞回
所以可以改成這樣
function* getResult(params) {
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
const gen = getResult()
function co(g) {
const nextObj = g.next();
if (nextObj.done) {
return;
}
nextObj.value.then(()=>{
co(g)
})
}
co(gen)

可以看到這樣就實作了,
完美,這個co其實也是大名鼎鼎的co函式的簡單寫法
本篇文章關于async 和 await的原理揭秘就到此為止了,再講下去就不禮貌了,
本文轉載于:
https://juejin.cn/post/7136424542238408718
如果對您有所幫助,歡迎您點個關注,我會定時更新技術檔案,大家一起討論學習,一起進步,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/509362.html
標籤:其他
上一篇:JS 模塊化 - 02 Common JS 模塊化規范
下一篇:JavaScript基礎知識
