1.async 函數(shù) & await
1.1. async含義
ES2017 標準引入了 async 函數(shù)辛藻,使得異步操作變得更加方便。
async 函數(shù)是 Generator 函數(shù)的語法糖谆奥。
什么是語法糖?
意指那些沒有給計算機語言添加新功能,而只是對人類來說更“甜蜜”的語法蜕着。語法糖往往給程序員提供了更實用的編碼方式,有益于更好的編碼風格红柱,更易讀承匣。不過其并沒有給語言添加什么新東西。反向還有語法鹽:
主要目的是通過反人類的語法锤悄,讓你更痛苦的寫代碼韧骗,雖然同樣能達到避免代碼書寫錯誤的效果,但是編程效率很低零聚,畢竟提高了語法學習門檻袍暴,讓人齁到憂傷些侍。。政模。
1.2. async的使用
async函數(shù)使用時就是將 Generator 函數(shù)的星號(*)替換成async岗宣,將yield替換成await,僅此而已淋样。
//創(chuàng)建異步函數(shù)
async function show() {
let result =await 20;
console.log(result);
}
show()
async function show (){
await '33'
}
let p1 = show();
1.2.1 await配合async使用
async function fn(){ // async 表示異步,這個函數(shù)里面有異步的任務
let result = await xxxx; // 表示等待await后面的結(jié)果需要等待,等出來在處理
}
1.3. async函數(shù)對 Generator 函數(shù)的區(qū)別:
(1)內(nèi)置執(zhí)行器耗式。
Generator 函數(shù)的執(zhí)行必須靠執(zhí)行器,而async函數(shù)自帶執(zhí)行器趁猴。也就是說刊咳,async函數(shù)的執(zhí)行,與普通函數(shù)一模一樣儡司,只要一行娱挨。
(2)更好的語義。
async和await枫慷,比起星號和yield让蕾,語義更清楚了。async表示函數(shù)里有異步操作或听,await表示緊跟在后面的表達式需要等待結(jié)果探孝。
(3)正常情況下,await命令后面是一個 Promise 對象誉裆。如果不是顿颅,會被轉(zhuǎn)成一個立即resolve的 Promise 對象。
(4)返回值是 Promise足丢。
async函數(shù)的返回值是 Promise 對象粱腻,這比 Generator 函數(shù)的返回值是 Iterator 對象方便多了。你可以用then方法指定下一步的操作斩跌。
進一步說绍些,async函數(shù)完全可以看作多個異步操作,包裝成的一個 Promise 對象耀鸦,而await命令就是內(nèi)部then命令的語法糖柬批。
async function show() {
let result =await new Promise((res)=>{ //后面跟Promise,里面定義一個回調(diào)函數(shù)袖订。await會始終等到后面的Promise調(diào)用then方法氮帐,把then方法的值取出來賦值給result
setTimeout(()=>{
res(50)
},3000)
});
console.log(result);
}
show()
async function show() {
let result = await new Promise((res) => { //后面跟Promise,里面定義一個回調(diào)函數(shù)洛姑。await會始終等到后面的Promise調(diào)用then方法上沐,把then方法的值取出來賦值給result
setTimeout(() => {
res(50)
}, 3000)
});
console.log(result);
return result + 20;
}
show()
let res = show();
console.log(res);
res.then((data) => { console.log(data); })
1.4. async 的特點
- await 只能放到async函數(shù)中使用
- 相比generator 語義化更強
- await后面可以是promise對象,也可以是數(shù)字,字符串,布爾值
- async 函數(shù)返回的是一個promise對象
- 只要await 語句后面的Promise的狀態(tài)變成reject,那么整個async函數(shù)會中斷執(zhí)行
1.4.1 驗證async函數(shù)返回一個promise對象
async function fn(){
}
console.log(fn()); //Promise
// 使用
async function fn(){
return 'welcome';
}
fn().then(res => {
console.log(res); // welcome
})
1.4.2 如果async函數(shù)中出錯
async function fn(){
throw new Error('Error 出錯了')
}
fn().then(res => {
console.log(res);
}).catch(err => {
console.log(err); // Error 出錯了
})
async function show() {
throw new Error('Error 出錯了')
}
let res = show();
console.log(res);
res.then((data) => { console.log(data); })
.catch(err => {
console.log(err); // Error 出錯了
})
async function show() {
try {
throw new Error('Error 出錯了')
let result = await 20;
console.log(result);
} catch (err) {
console.log(err)
}
}
let promise = show()
promise.then((data) => console.log(data))
1.4.3 如果await后面的語句出錯,函數(shù)后面將中斷執(zhí)行
錯誤在成功之后,錯誤和成功都會執(zhí)行
async function fn(){
let a = await Promise.resolve("成功了");
console.log(a);
await Promise.reject('出錯了') //await 后面如果是失敗狀態(tài)promise 這條語句后面的代碼都不會執(zhí)行
}
fn().then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
// 打印結(jié)果
// 成功了
// 出錯了
但是如果錯誤在前,成功將不會執(zhí)行
async function fn(){
await Promise.reject('出錯了')
let a = await Promise.resolve("成功了");
console.log(a);
}
fn().then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
// 打印結(jié)果
// 出錯了
1.5. 解決async函數(shù)中的報錯
如何解決async函數(shù)中拋出錯誤,影響后續(xù)代碼執(zhí)行;
這個問題比較嚴重,雖然是async的特點,但是我又不知道程序什么時候出錯,所以我不希望出錯的代碼影響后續(xù)運行,導致程序中斷
1.5.1使用 try { } catch (){}
async function fn(){
try{
await Promise.reject('出錯了')
}catch(e){
let a = await Promise.resolve("成功了");
console.log(a);
}
}
1.5.2 添加catch 捕獲錯誤
本來await后面的就是promise,那么我們就可以直接使用catch處理
async function fn(){
await Promise.reject('出錯了').catch(err=>{
console.log(err);
})
let a = await Promise.resolve("成功了");
console.log(a);
}
其實跟網(wǎng)絡打交道的都不保險,你不可能給每一個await后面的promise對象都加catch
1.5.3 統(tǒng)一捕獲錯誤
個人建議,只要有await的地方都try catch掉 然后統(tǒng)一處理結(jié)果
try {
let f1 = await Promise.resolve('成功了');
let f2 = await Promise.resolve('成功了');
let f3 = await Promise.reject('出錯了');
}catch(e){}
1.5.4 也可以是用Promise.all()方法
如果你多次請求的數(shù)據(jù)之間沒有關(guān)聯(lián),就可以使用Promise.all()
// async
async function fn(){
let [f1,f2,f3] = await Promise.all([
Promise.resolve('成功了1'),
Promise.resolve('成功了2'),
Promise.resolve('成功了3')
])
console.log(f1);
console.log(f2);
console.log(f3);
}
fn();
同時配合解構(gòu)處理
例子:
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script>
async function show() {
let p1 = await new Promise((res, rej) => {
$.ajax({
url: 'https://jsonplaceholder.typicode.com/todos/1',
success: function (data) {
console.log(data);
res()
},
error: function (err) {
rej()
}
})
});
let p2 = await new Promise((res, rej) => {
$.ajax({
url: 'https://jsonplaceholder.typicode.com/todos/2',
success: function (data) {
console.log(data);
res()
},
error: function (err) {
rej()
}
})
});
}
let pp = show();
generator只是一個過渡期,強烈建議大家用async就可以了