Promise 基本用法(Promise Syntax):new Promise( function(resolve, reject) {…} );
通過創建 Promise 對象開啓一個異步操作的過程,一般用幾步完成多次異步操作:
- new Promise(fn) 返回一個Promise 對象
- 在fn 中指定異步等處理
- 處理結果正常的話,調用resolve(處理結果值)
- 處理結果錯誤的話,調用reject(Error對象)
function loadScript(src) {
return new Promise((resolve, reject) => {
let script = document.createElement('script')
script.src = src
script.onload = () => resolve(src)
script.onerror = (err) => reject(err)
document.head.append(script)
})
}
loadScript('./1.js')
.then(loadScript('./2.js'))
.then(loadScript('./3.js'))
Promise 內部狀態(pending、fulfilled、rejected),Promise 對象根據狀態來確定執行哪個方法。Promise 在實例化的時候狀態默認爲 pending,當異步操作完成,狀態會被修改爲 fulfilled,當異步操作遇到異常,狀態會被修改爲 rejected。而此種狀態變化是單向且不可逆轉的,已經確定的狀態(fulfilled/rejected)無法轉回初始狀態(pending),而且只能是從 pending 到 fulfilled 或者 rejected
串行異步操作——Promise.prototype.then():then 是 promise 原型上的方法,只有promise可以調用then
基本語法:promise.then(onFulfilled, onRejected):then 支持兩個參數,這兩個參數都是函數類型,第一個參數必選,第二個參數可選。這兩個函數分別對應是 Promise 對象的resolve 和 reject 這兩個方法,如果傳入的這兩個參數是非函數或被遺漏,會返回一個空的 promise 對象,以保證只要調用 promise 對象就一定可以返回一個 promise 對象,所以可以鏈式調用 .then()。
寫法改造:
function loadScript(src) {
return new Promise((resolve, reject) => {
let script = document.createElement('script')
script.src = src
script.onload = () => resolve(src)
script.onerror = (err) => reject(err)
document.head.append(script)
})
}
loadScript('./1.js')
.then(() => {
return loadScript('./4.js') // 返回 promise 對象影響下一個.then()
}, (err) => {
console.log(err)
})
.then(() => {
loadScript('./3.js')
}, (err) => {
console.log(err)
})
Promise.resolve() 和 Promise.reject() 是 Promise 的靜態方法,是 new Promise() 方法的快捷方式。
Promise.prototype.catch(),用 Promise 對象的 catch 方法來捕獲異步操作過程中出現的任何異常,當 promise 狀態改爲rejected時捕獲錯誤。
new Error 不會觸發 catch,而是 reject,不建議在 Promise 內部使用 throw 來觸發異常,而是使用 reject(new Error())
的方式來做,因爲 throw 的方式並沒有改變 Promise 的狀態
並行異步操作——Promise.all():滿足所有任務都完成的條件
生成並返回一個新的 Promise 對象,所以它可以使用 Promise 實例的所有方法。參數傳遞promise數組中所有的 Promise 對象都變爲resolve的時候,該方法纔會返回, 新創建的 Promise 則會使用這些 promise 的值。如果參數中的任何一個promise爲reject的話,則整個Promise.all調用會立即終止,並返回一個reject的新的 Promise 對象。由於參數數組中的每個元素都是由 Promise.resolve 包裝(wrap)的,所以Paomise.all 可以處理不同類型的 promose對象。
const p1 = Promise.resolve(1) //使用Promise進行一個異步操作,返回結果是1
const p2 = Promise.resolve(2)
const p3 = Promise.resolve(3)
Promise.all([p1, p2, p3]).then((value) => {
console.log(value) //[1, 2, 3]
})
Promise.race():先到先得
Promise.race 生成並返回一個新的 Promise 對象。參數 promise 數組中的任何一個 Promise 對象如果變爲 resolve 或者 reject 的話, 該函數就會返回,並使用這個 Promise 對象的值進行 resolve 或者 reject。
思考:
1、按順序加載腳本太直觀看出順序執行的過程,如果按順序延時執行是不是更好理解?
2、請用 Promise 實現一個接口。
const p1 = () => {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve(1)
}, 1000)
})
}
const p2 = () => {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve(2)
}, 0)
})
}
Promise.race([p1(), p2()]).then((value) => {
console.log(value) // 2
})