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)
}