promise
Promise物件代表一個非同步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。一旦成功就不允許失敗,一旦失敗就不允許成功。
function Promise(excutor) {
let self = this
self.status = 'pending'
self.value = null
self.reason = null
function resolve(value) {
if (self.status === 'pending') {
self.value = value
self.status = 'fulfilled'
}
}
function reject(reason) {
if (self.status === 'pending') {
self.reason = reason
self.status = 'rejected'
}
}
try {
excutor(resolve, reject)
} catch (err) {
reject(err)
}
}
複製程式碼
Promise接收一個函式作為引數,該函式有兩個引數,一個是resolve
,表示成功時執行的函式,一個是reject
,表示失敗失敗時執行的函式。resolve
執行時傳入的引數會作為then
方法中第一個回撥函式的引數,reject
執行傳入的引數會作為then
方法中第二函式回撥的引數。
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this
if (self.status === 'fulfilled') {
onFulfilled(self.value)
}
if (self.status === 'rejected') {
onRejected(self.reason)
}
}
複製程式碼
Promise中常常會寫一些非同步程式碼,等到非同步操作執行完成才會觸發resolve
或者reject
函式,當執行then
方法的時候此時的狀態還是初始的pending
狀態,所以為了能取到引數,我們可以通過釋出訂閱模式來寫。
基本呼叫
function Promise(excutor) {
let self = this
self.status = 'pending'
self.value = null
self.reason = null
self.onFulfilledCallbacks = []
self.onRejectedCallbacks = []
function resolve(value) {
if (self.status === 'pending') {
self.value = value
self.status = 'fulfilled'
self.onFulfilledCallbacks.forEach(item => item(self.value))
}
}
function reject(reason) {
if (self.status === 'pending') {
self.reason = reason
self.status = 'rejected'
self.onRejectedCallbacks.forEach(item => item(self.reason))
}
}
try {
excutor(resolve, reject)
} catch (err) {
reject(err)
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this
if (self.status === 'fulfilled') {
onFulfilled(self.value)
}
if (self.status === 'rejected') {
onRejected(self.reason)
}
if (self.status === 'pending') {
self.onFulfilledCallbacks.push(onFulfilled)
self.onRejectedCallbacks.push(onRejected)
}
}
複製程式碼
我們都知道Promise有一個特點,就是鏈式呼叫,當執行then
完成後可以繼續執行then
方法,其實他的原理就是通過返回一個新的Promise實現的,那麼then
方法中的程式碼就可以寫成下面這樣
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this
if (self.status === 'fulfilled') {
return new Promise((resolve, reject) => {
onFulfilled(self.value)
})
}
if (self.status === 'rejected') {
return new Promise((resolve, reject) => {
onRejected(self.reason)
})
}
if (self.status === 'pending') {
return new Promise((resolve, reject) => {
self.onFulfilledCallbacks.push(onFulfilled)
self.onRejectedCallbacks.push(onRejected)
})
}
}
複製程式碼
then
方法接收的兩個函式中,可以通過return把值傳給下一個步,也可以返回一個新的Promise把值傳給下一步,then
方法執行的時候有個特點,就是為了保證鏈式呼叫,上一次then
中不管你是成功還是失敗都會把引數作為下一個then
中成功時回撥的引數,舉個例子
let promise1 = new Promise((resolve, reject) => {
reject('1')
})
let promise2 = promise1.then((res) => {
return 1
}, (err) => {
return 2
})
promise2.then((res) => {
console.log(res)//不管上一次then執行的那個回撥函式,在這裡都可以接收到引數
})
複製程式碼
鏈式呼叫
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this
if (self.status === 'fulfilled') {
return new Promise((resolve, reject) => {
try {
let x = onFulfilled(self.value)
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (err) {
reject(err)
}
})
}
if (self.status === 'rejected') {
return new Promise((resolve, reject) => {
try {
let x = onRejected(self.reason)
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (err) {
reject(err)
}
})
}
if (self.status === 'pending') {
return new Promise((resolve, reject) => {
self.onFulfilledCallbacks.push(() => {
let x = onFulfilled(self.value)
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
self.onRejectedCallbacks.push(() => {
let x = onRejected(self.reason)
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
})
}
}
複製程式碼
注意不管是成功時的回撥還是失敗時的回撥,都有try/catch
包裹,不管成功還是失敗都會被下一次resolve
接收到,只有程式碼報錯才會執行reject
,處理特殊情況,then
中沒有傳成功時的回撥函式或失敗時的回撥函式,程式碼會報錯,所以要指定預設值
Promise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (data) {return data}
onRejected = typeof onRejected === 'function' ? onRejected : function (err) {throw err}
let self = this
if (self.status === 'fulfilled') {
return new Promise((resolve, reject) => {
try {
let x = onFulfilled(self.value)
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (err) {
reject(err)
}
})
}
if (self.status === 'rejected') {
return new Promise((resolve, reject) => {
try {
let x = onRejected(self.reason)
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (err) {
reject(err)
}
})
}
if (self.status === 'pending') {
return new Promise((resolve, reject) => {
self.onFulfilledCallbacks.push(() => {
let x = onFulfilled(self.value)
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
self.onRejectedCallbacks.push(() => {
let x = onRejected(self.reason)
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
})
}
}
複製程式碼
指定預設值得時候注意失敗時要繼續丟擲錯誤,因為只有程式碼報錯才會走reject
函式
catch方法
其實catch
方法就是then
方法的簡寫
Promise.prototype.catch = function (fn) {
return this.then(null, fn)
}
複製程式碼
完整程式碼
function Promise(excutor) {
let self = this
self.status = 'pending'
self.value = null
self.reason = null
self.onFulfilledCallbacks = []
self.onRejectedCallbacks = []
function resolve(value) {
if (self.status === 'pending') {
self.value = value
self.status = 'fulfilled'
self.onFulfilledCallbacks.forEach(item => item())
}
}
function reject(reason) {
if (self.status === 'pending') {
self.reason = reason
self.status = 'rejected'
self.onRejectedCallbacks.forEach(item => item())
}
}
try {
excutor(resolve, reject)
} catch (err) {
reject(err)
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (data) {resolve(data)}
onRejected = typeof onRejected === 'function' ? onRejected : function (err) {throw err}
let self = this
if (self.status === 'fulfilled') {
return new Promise((resolve, reject) => {
try {
let x = onFulfilled(self.value)
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (err) {
reject(err)
}
})
}
if (self.status === 'rejected') {
return new Promise((resolve, reject) => {
try {
let x = onRejected(self.reason)
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (err) {
reject(err)
}
})
}
if (self.status === 'pending') {
return new Promise((resolve, reject) => {
self.onFulfilledCallbacks.push(() => {
let x = onFulfilled(self.value)
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
self.onRejectedCallbacks.push(() => {
let x = onRejected(self.reason)
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
})
}
}
Promise.prototype.catch = function (fn) {
return this.then(null, fn)
}
複製程式碼