這是我參與8月更文挑戰的第2天,活動詳情查看:8月更文挑戰前端
複習Promise知識,關於它的概念,使用方式等,還有注意事項。 參考依然是阮一峯老師的 ESCMAScript6入門 es6.ruanyifeng.com/ ,寫它的緣由是在項目中能常常的使用到Promise作異步處理,,但對它並無系統性的瞭解。vue
簡單說下,Promise是一種js單線程的異步處理方案,在對後端的接口請求中咱們常常會用到,相信大多數前端都對這個不陌生。ES6將Promise進行來便準規範。es6
promise有三種狀態,而且具有了狀態不受干擾以及狀態一旦改變就不會再變的特性。正則表達式
三種狀態分別是mongodb
須要注意的是,一旦執行,中途就沒法取消,若是不設置回調函數,Promise內部會拋出錯誤,並且在pending狀態中,不知道會進展到哪一個階段。後端
在前端的使用過程當中,通常在請求的時候都會用到,有的用來封裝請求,也有在store中使用,固然也是封裝請求的。大體以下api
function getUserInfo(data) {
return new Promise((resolve, reject) => {
// 接口的方法
if(true) {
resolve('返回參數')
} else {
reject('錯誤的信息')
}
})
}
getUserInfo(data).then(res => {
console.log(res)
}).catch(res => {
console.log(res)
})
複製代碼
這個應該是最多見的使用方式,還有就是Promise.all()的方式,會在後邊寫到。數組
下邊一個異步加載圖片的例子promise
function loadImageAsync(url) {
return new Promise((resolve, reject) => {
const image = new Image()
image.onload = function() {
resolve(image)
}
image.onerror = function() {
reject(new Error('Could not load image at '+ url))
}
image.src = url
})
}
複製代碼
這裏比較重要的一點仍是promise的已成功 和已失敗兩個回調,在獲得圖片路徑的時候,使用resolve來返回正確的地址,錯誤的時候返回錯誤的地址。markdown
在promise中,通常是從進行中到已成功或已失敗。在這個過程當中是有回調地址的,若是當前回調地址爲一個新的promise,那麼當前這個promise的狀態實際上是取決於當前回調這個promise的狀態的。
例如:
const p1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('p1'), 3000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve(p1), 1000)
})
p2.then(result => console.log(result,'result')) // p1 result
.catch(error => console.log(error,'error'))
複製代碼
當前這個例子彷佛是看不出來的,p2是成功回調,p1也是成功回調。對比第二個例子就能清晰看出來了
const p1 = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('錯了')), 3000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve(p1), 1000)
})
p2.then(result => console.log(result,'result'))
.catch(error => console.log(error,'error')) // Error: 錯了
複製代碼
兩個比較,咱們就能夠清晰認識到這一點。
Promise 實例具備then方法,then方法是定義在原型對象Promise.prototype上的。then方法能夠鏈式調用,通俗說就是葫蘆娃救爺爺,一個接一個。
一樣,promise.prototype上還有catch,上一個是處理回調的,這個是用來處理錯誤的。
兩種等價的寫法
// 寫法一
const promise = new Promise(function(resolve, reject) {
try {
throw new Error('test');
} catch(e) {
reject(e);
}
});
promise.catch(function(error) {
console.log(error);
});
// 寫法二
const promise = new Promise(function(resolve, reject) {
reject(new Error('test'));
});
promise.catch(function(error) {
console.log(error);
});
// 比較上面兩種寫法,能夠發現reject()方法的做用,等同於拋出錯誤。
複製代碼
並且Promise 對象的錯誤會一直向後傳遞,直到被捕獲
finally()
方法用於指定無論 Promise 對象最後狀態如何,都會執行的操做。該方法是 ES2018 引入標準的。相對用的比較少,在特定環境下,finally 也會有奇效,具體看業務場景。
Promise.all()
方法用於將多個 Promise 實例,包裝成一個新的 Promise 實例。
這個方法,在nuxtjs作服務端渲染的時候會用的比較多一些。用的方式也很特別。打包一塊兒搞,所有返回後才走then方法。 狀態有兩種:所有爲fulfilled,狀態就是fuifilled;若是有一個是rejected,那麼狀態就爲rejected.
所有爲fulfilled
const p1 = new Promise((resolve, reject) => {
resolve('p1');
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
resolve('p2');
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(result => console.log(result,'then')) // ["p1", "p2"] "then"
.catch(e => console.log(e,'catch'));
複製代碼
有一個是rejected
const p1 = new Promise((resolve, reject) => {
resolve('p1');
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
throw new Error('報錯了');
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(result => console.log(result,'then'))
.catch(e => console.log(e,'catch'));
複製代碼
再看下面的例子
const p1 = new Promise((resolve, reject) => {
resolve('p1');
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
throw new Error('報錯了');
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(result => console.log(result,'then'))
.catch(e => console.log(e,'catch'));
複製代碼
這個彷佛咱們以前所說的不一致,主要是由於p2中使用了catch, p2首先進入rejected,可是由於有本身的catch方法,方法會返回一個新的實例,p2指向的實際是這個實例。實例執行完成後也變爲了resolved,所以p1,p2都進入了then方法。
這個方法和all()相反,那個率先改變的 Promise 實例的返回值,就傳遞給回調函數
const p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'p1')
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
resolve('p2');
})
.then(result => result)
.catch(e => e);
Promise.race([p1, p2])
.then(result => console.log(result,'then')) // p2 then
.catch(e => console.log(e,'catch'));
複製代碼
若是將定時器去掉,你會發現一直執行的都是p1
Promise.allSettled()
方法接受一組 Promise 實例做爲參數,包裝成一個新的 Promise 實例。只有等到全部這些參數實例都返回結果,不論是fulfilled
仍是rejected
,包裝實例纔會結束。該方法返回的實例,狀態老是fulfilled,不會變成rejected,接受的參數也是一個數組。
const promises = [
fetch('/api-1'),
fetch('/api-2'),
fetch('/api-3'),
];
await Promise.allSettled(promises);
removeLoadingIndicator();
複製代碼
該方法接受一組 Promise 實例做爲參數,包裝成一個新的 Promise 實例返回。
Promise.any([
fetch('https://v8.dev/').then(() => 'home'),
fetch('https://v8.dev/blog').then(() => 'blog'),
fetch('https://v8.dev/docs').then(() => 'docs')
]).then((first) => { // 只要有一個 fetch() 請求成功
console.log(first);
}).catch((error) => { // 全部三個 fetch() 所有請求失敗
console.log(error);
});
複製代碼
以上就是回顧的全部知識點,有不足指出,還請多多指教!!!