一種更優的異步編程統一方案,可是直接使用傳統回調方式去完成複雜的異步流程會形成大量的回調問題(回調地獄),CommonJS社區提出了Promise的規範,目的就是爲異步編程提供更合理更規範的統一解決方案,在ES2015中被標準化,成爲語言規範。javascript
Promise就是一個對象,用來表示一個異步任務最終結束以後到底是成功仍是失敗,就像是內部對外界作出了一個承諾,一開始這個承諾是待定的狀態(pending),最終有多是成功(Fulfilled)對應的回調函數爲onFulfilled,也多是失敗(Rejected)對應的回調函數爲onRejected。java
示例:node
// Promise接收一個函數,函數有兩個參數(都是函數),resolve和reject
const promise = new Promise(function (resolve, reject) {
// resolve函數的做用就是把Promise的狀態修改成Fulfilled
// 成功的結果就是經過這個resolve傳遞出去
resolve(100)
// reject函數的做用就是把Promise的狀態修改成Rejected
// 失敗的結果經過這個reject傳遞出去
// reject傳遞的參數通常是一個錯誤對象,描述錯誤的緣由
reject(new Error('promise rejected'))
})
promise.then(function(value) {
// 當返回resolve時會調用這個回調函數
console.log('resolve', value) // => 100
}, function(err) {
// 當返回reject時會調用這個回調函數
console.log('rejected', err) // => Error對象
})
複製代碼
onRejected是爲Promise中的異常作一些處理,如:Promise主動調用reject方法、調用一個不存的方法、主動拋出一個Error異常。ajax
經過Promise的catch方法捕獲異常編程
promise.then(function(value) {
// 當返回resolve時會調用這個回調函數
console.log('resolve', value) // => 100
})
.catch(function(err) { // catch方法其實就是reject方法的一個別名
// 當返回reject時會調用這個回調函數
console.log('rejected', err) // => Error對象
})
複製代碼
catch不then方法第二個參數捕獲異常的不一樣點:json
若是在Promise鏈條中發生異常,這個異常會被一直日後傳遞,直到被捕獲,因此catch方法更像是給整個鏈條註冊的異常捕獲。api
resolve方法直接將值返回數組
示例:promise
Promise.resolve('foo')
.then(function(value) {
console.log(value) // => foo
})
// 上邊獲得的value就和下邊這種同樣
new Promise(function(resolve, reject) {
resolve('foo')
})
複製代碼
使用Promise對象的靜態方法resolve包裝一個Promise,獲得的是本來被包裝的Promise 示例:異步
let promise = ajax('/api/users.json')
let promise2 = Promise.resolve(promise)
console.log(promise === promise2) // => true
複製代碼
Promise的resolve方法返回一個帶有then方法的對象,這個對象也具備onFulfilled方法時,咱們也能夠經過then方法拿到返回的值 示例:
Promise.resolve({
then: function(onFulfilled, onRejected) {
onFulfilled('foo')
}
})
.then(function(value) {
console.log(value) // => foo
})
複製代碼
與resolve靜態方法對應的是reject靜態方法,reject靜態方法返回就是錯誤信息,使用上和resolve相似,如:Promise.reject(new Error('xxx'))
當有多個異步任務須要同時處理時,在以前是經過定義一個計數器的形式來判斷全部異步任務是否都執行完成。在Promise中如今給咱們提供了一個能夠同時處理多個異步任務的方法:all。
示例:
let promise = Promise.all([
ajax('/api/users.json'),
ajax('/api/posts.json')
])
// all方法會當全部異步任務都執行完成以後返回一個Promise對象
// 只有當全部異步任務都成功時才返回resolve,不然返回reject
peomise.then(function(value) {
// value傳遞的爲一個數組,數組中包括全部異步任務的執行結果
console.log(value) // => [xx, xx]
})
複製代碼
race方法也一樣能夠將多個Promise對象組合爲一個全新的Promise對象,與all方法不一樣的是all方法等待全部異步任務結束以後結束;race方法是隻會等待第一個異步任務結束後結束,也就是隻要其中任何一個異步任務完成以後race方法就會結束。
示例:
const request = ajax('/api/posts.json')
const timer = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('timeout')), 500)
})
Promise.race([
request,
timer
])
.then(value => {
// 若是500ms之內request方法成功則執行成功的回調
console.log(value)
})
.catch(err => {
// 若是500ms之內request方法沒有成功,則執行失敗的回調
console.log(err)
})
複製代碼
回調隊列中任務一般被稱做宏任務,宏任務執行過程當中可能會添加一些額外的需求,新添加的需求能夠選擇做爲一個新的宏任務進入到隊列中排隊,例如setTimeout會在宏任務中排隊,也能夠做爲一個微任務,直接在當前任務結束以後當即執行。 Promise的回調做爲微任務執行,在本輪調用結束的末尾當即執行。 微任務:爲了提升總體的響應能力 目前絕大多數異步調用都是做爲宏任務執行,而Promise對象、MutationObserver、node中的process.nextTick是做爲微任務執行
示例:
console.log('begin')
// 做爲宏任務執行
setTimeout(() => {
console.log('timer')
}, 0)
// 做爲微任務執行
Promise.resolve()
.then(() => {
console.log('promise')
})
.then(() => {
console.log('promise2')
})
console.log('end')
// => begin => end => promise => promise2 => timer
複製代碼