Promise和Async/Await用法整理
Promise和Async/Await用法整理 - 簡書 (jianshu.com)
1.Promise
1.簡介
Promise,簡單來說就是一個容器,裡面儲存著某個未來才會結束的時間(通常是一個非同步操作的結果)
Promise物件的基本語法:
new Promise((resolve,reject) => {
//.....
});
從語法上來說,Promise是一個物件,從它可以獲取非同步操作的訊息。
基本語法:
let p = new Promise((resolve,reject) => {
//...
resolve('success')
});
p.then(result => {
console.log(result);//success
});
Promise物件特點和三個狀態:
這裡寫圖片描述
例如:
let p = new Promise((resolve,reject) => {
//...
resolve('success');
console.log('after resolve');
reject('error');
});
p.then(result => {
console.log(result);
});
p.catch(result => {
console.log(result);
})
執行結果:
after resolve
success
resolve下面的語句其實是可以執行的,那麼為什麼reject的狀態資訊在下面沒有接受到呢?這就是因為Promise物件的特點:狀態的凝固。new出一個Promise物件時,這個物件的起始狀態就是Pending狀態,在根據resolve或reject返回Fulfilled狀態/Rejected狀態。
2.
這裡寫圖片描述Then分別接受resolve和reject的資訊,有三種引數形式,第三種比較“怪異”,只用來接收做reject處理。
eg:
let p = new Promise((resolve,reject) => {
//...
let random = Math.random();//小於1大於0
if(random > 0.4) {
resolve('random > 0.4');
}else {
reject('random <= 0.4');
}
});
p.then(result => {
console.log('resolve',result);
}, result => {
console.log('reject',result);
});
3.鏈式呼叫
我們來執行一段程式碼:
let p = new Promise((resolve,reject) => {
reject('reject');
});
let resultP = p.then(null,result => {
console.log(result);
});
console.log(resultP);
結果:
Promise { <pending> }
reject
js的執行順序就是這樣,同步->非同步->回撥,在同步執行的時候,Promise物件還處於pending的狀態,也說明了這個then返回的是一個Promise物件。
而且必須在then裡面給一個返回值,才能繼續呼叫,否則undefined。
eg:
let p = new Promise((resolve,reject) => {
reject('error');
});
let resultP = p.then(null,result => {
console.log(result);
return 123;
});
// console.log(resultP);
resultP.then(tmp => {
console.log(tmp);
})
結果:
error
123
4.catch
這裡寫圖片描述eg:
let p = new Promise((resolve,reject) => {
reject('error');
});
p.catch(result => {
console.log(result);
})
那這個catch的返回值是什麼呢:
和上面then是一樣的。
5.Promise.resolve()
這裡寫圖片描述傳一個普通的物件:
// let p1 =Promise.resolve(123);
let p1 =Promise.resolve({name:'xixi',age:'xxxx'});
p1.then(result => {
console.log(result);
});
如果是Promise物件呢,直接返回
let p = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('success');
},500);
});
let pp = Promise.resolve(p);
pp.then(result => {
console.log(result);
});
console.log(pp == p);
結果:
true
success
6.Promise.reject()
這裡寫圖片描述eg:
let p = Promise.reject(123);
console.log(p);
p.then(result => {
console.log(result);
}).catch(result => {
console.log('catch',result);
})
結果:
Promise { <rejected> 123 }
catch 123
7.Promise.all()
這裡寫圖片描述eg:
let p1 = Promise.resolve(123);
let p2 = Promise.resolve('hello');
let p3 = Promise.resolve('success');
Promise.all([p1,p2,p3]).then(result => {
console.log(result);
})
結果:
[ 123, 'hello', 'success' ]
成功之後就是陣列型別,當所有狀態都是成功狀態才返回陣列,只要其中有一個的物件是reject的,就返回reject的狀態值。
eg:
let p1 = Promise.resolve(123);
let p2 = Promise.resolve('hello');
let p3 = Promise.resolve('success');
let p4 = Promise.reject('error');
// Promise.all([p1,p2,p3]).then(result => {
// console.log(result);
// });
Promise.all([p1,p2,p4]).then(result => {
console.log(result);
}).catch(result => {
console.log(result);
});
結果:
error
又一個eg:
//用sleep來模仿瀏覽器的AJAX請求
function sleep(wait) {
return new Promise((res,rej) => {
setTimeout(() => {
res(wait);
},wait);
});
}
let p1 = sleep(500);
let p2 = sleep(500);
let p3 = sleep(1000);
Promise.all([p1,p2,p3]).then(result => {
console.log(result);
//.....
//loading
});
8.Promise.race
這裡寫圖片描述和all同樣接受多個物件,不同的是,race()接受的物件中,哪個物件返回的快就返回哪個物件,就如race直譯的賽跑這樣。如果物件其中有reject狀態的,必須catch捕捉到,如果返回的夠快,就返回這個狀態。race最終返回的只有一個值。
eg:
//用sleep來模仿瀏覽器的AJAX請求
function sleep(wait) {
return new Promise((res,rej) => {
setTimeout(() => {
res(wait);
},wait);
});
}
let p1 = sleep(500);
let p0 = sleep(2000);
Promise.race([p1,p0]).then(result => {
console.log(result);
});
let p2 = new Promise((resolve,reject) => {
setTimeout(()=>{
reject('error');
},1000);
});
Promise.race([p0,p2]).then(result => {
console.log(result);
}).catch(result => {
console.log(result);
});
500
error
9.異常處理
這裡寫圖片描述為什麼說安靜,一個例子,Pormise內部的錯誤外界用try-catch捕捉不到
eg:
try {
let p = new Promise((resolve, reject) => {
throw new Error("I'm error");
// reject(new Error("I'm Error"));
});
}catch(e) {
console.log('catch',e);
}
結果什麼都沒列印。
但是丟擲的錯誤可以通過catch來捕捉:
// try {
let p = new Promise((resolve, reject) => {
throw new Error("I'm error");
// reject(new Error("I'm Error"));
});
// }catch(e) {
// console.log('catch',e);
// }
p.catch(result => {
console.log(result);
});
這樣就捕捉到錯誤。所以:
這裡寫圖片描述
2.Async-Await
1.簡介:
這裡寫圖片描述 這裡寫圖片描述async和await在幹什麼,async用於申明一個function是非同步的,而await可以認為是async wait的簡寫,等待一個非同步方法執行完成。
2.基本語法
這裡寫圖片描述在Chrome裡申明這樣一個函式,可以在控制檯看到返回的其實就是一個Promise物件。
擴充套件需要了解的就是Chrome現在也支援asyncFunction,可以在Chrome控制檯測試:
console.log(async function(){}.constructor);
ƒ AsyncFunction() { [native code] }
3.規則
這裡寫圖片描述如圖,await放在普通函式裡是會報錯的。
這裡寫圖片描述eg:
async function demo() {
let result = await Promise.resolve(123);
console.log(result);
}
demo();
4.應用
Promise雖然一方面解決了callback的回撥地獄,但是相對的把回撥“縱向發展”了,形成了一個回撥鏈。eg:
function sleep(wait) {
return new Promise((res,rej) => {
setTimeout(() => {
res(wait);
},wait);
});
}
/*
let p1 = sleep(100);
let p2 = sleep(200);
let p =*/
sleep(100).then(result => {
return sleep(result + 100);
}).then(result02 => {
return sleep(result02 + 100);
}).then(result03 => {
console.log(result03);
})
控制檯:
300
後面的結果都是依賴前面的結果。
改成async/await寫法就是:
async function demo() {
let result01 = await sleep(100);
//上一個await執行之後才會執行下一句
let result02 = await sleep(result01 + 100);
let result03 = await sleep(result02 + 100);
// console.log(result03);
return result03;
}
demo().then(result => {
console.log(result);
});
因為async返回的也是promise物件,所以用then接受就行了。
結果:
300
需要注意的就是await是強制把非同步變成了同步,這一句程式碼執行完,才會執行下一句。
5.錯誤處理
這裡寫圖片描述如果是reject狀態,可以用try-catch捕捉
eg:
let p = new Promise((resolve,reject) => {
setTimeout(() => {
reject('error');
},1000);
});
async function demo(params) {
try {
let result = await p;
}catch(e) {
console.log(e);
}
}
demo();
結果:
error
這是基本的錯誤處理,但是當內部出現一些錯誤時,和上面Promise有點類似,demo()函式不會報錯,還是需要catch回撥捕捉。這就是內部的錯誤被“靜默”處理了。
let p = new Promise((resolve,reject) => {
setTimeout(() => {
reject('error');
},1000);
});
async function demo(params) {
// try {
let result = name;
// }catch(e) {
// console.log(e);
// }
}
demo().catch((err) => {
console.log(err);
})
6.注意你的並行執行和迴圈
比如上面的例子:
這裡寫圖片描述
如果這三個是你想非同步發出的AJAX請求,在這段程式碼裡其實是同步的,第一個發出去才會發第二個,所以async/await需要謹慎使用。
這裡寫圖片描述現在有一些forEach或者map的迴圈裡,比如在forEach裡使用await,這時候的上下文就變成了array,而不是async function,就會報錯。這時候你就要想到是什麼錯誤。
作者:Lawliet_ZMZ
連結:https://www.jianshu.com/p/fe0159f8beb4
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。