正文
new Promis()时接收一个executor函数作为参数,该函数会立即执行,函数中有两个参数,它们也是函数,分别是resolve和reject,函数同步执行一定要放到try…catch中,否则无法进行错误捕获。
基础框架
function MyPromise(executor) {
function resolve(value) {
}
function reject(reason) {
}
try {
executor(resolve, reject);
} catch (reason) {
reject(reason);
}
}
module.exports = MyPromise;
resolve()接收Promise成功值value,reject接收Promise失败原因reason。
MyPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function MyPromise(executor) {
let self = this
self.state = PENDING
self.value = null
self.reason = null
self.onFulfilledCallbacks = []
self.onRejectedCallbacks = []
function resolve(value) {
if (self.state === PENDING) {
self.state = FULFILLED
self.value = value
self.onFulfilledCallbacks.forEach(function (fulfilledCallback) {
fulfilledCallback()
})
}
}
function reject(reason) {
if (self.state === PENDING) {
self.state = REJECTED
self.reason = reason
self.onRejectedCallbacks.forEach(function (rejectedCallback) {
rejectedCallback()
})
}
}
try {
executor(resolve, reject)
} catch (reason) {
reject(reason)
}
}
// 添加then方法
/**
* Promise拥有一个then方法,接收两个函数onFulFilled和onRejected,分别
作为Promise成功和失败的回调。所以,在then方法中我们需要对状态state进行判断,
如果是fulfilled,则执行onFulfilled(value)方法,如果是rejected,则执行onRejected(reason)方法。
*/
MyPromise.prototype.then = function (onFulfilled, onRejected) {
let self = this
let promise2 = null
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => {return value}
onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}
promise2 = new MyPromise((resolve, reject) => {
if (self.state === PENDING) {
self.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(self.value)
self.resolvePromise(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
}, 0);
})
self.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(self.reason)
self.resolvePromise(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
}, 0);
})
}
if (self.state === FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(self.value)
self.resolvePromise(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
}, 0);
}
if (self.state === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(self.reason)
self.resolvePromise(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
}, 0);
}
})
return promise2
}
/**
* resolvePromise()是用来解析then()回调函数中返回的仍是一个Promise,这个Promise有可能
* 是我们自己的,有可能是别的库实现的,也有可能是一个具有then()方法的对象,所以这里
* 靠resolvePromise()来实现统一处理。
* @param {*} promise2
* @param {*} x
* @param {*} resolve
* @param {*} reject
*/
MyPromise.prototype.resolvePromise = function(promise2, x, resolve, reject) {
let self = this
let called = false // called 防止多次调用
if (promise2 === x) {
return reject(new TypeError('循环引用'))
}
if (x !== null && Object.prototype.toString.call(x) === '[object Object]' || Object.prototype.toString.call(x) === '[object Function]') {
// x是对象或者函数
try {
let then = x.then
if (typeof then === 'function') {
then.call(x, y => {
// 别人的Promise的then方法可能设置了getter等,使用called防止多次调用then方法
if (called) return
called = true
// 成功值y有可能还是promise或者是具有then方法等,再次resolvePromise,直到成功值为基本类型或者非thenable
self.resolvePromise(promise2, y, resolve, reject)
}, reason => {
if (called) return
called = true
reject(reason)
})
} else {
if (called) return
called = true
resolve(x)
}
} catch (reason) {
if (called) return
called = true
reject(reason)
}
} else {
// x是普通值,直接resolve
resolve(x)
}
}
/**
* then()方法的onFulfilled和onRejected回调函数都不是必传项,如果不传,那么我们就无法接收reject(reason)中的错误,
* 这时我们可以通过链式调用catch()方法用来接收错误。
* @param {*} onRejected
*/
MyPromise.prototype.catch = function(onRejected) {
return this.then(null, onRejected)
}
/**
* finally是某些库对Promise实现的一个扩展方法,无论是resolve还是reject, 都会走finally方法。
* @param {*} fn
*/
MyPromise.prototype.finally = function(fn) {
return this.then(value => {
fn()
return value
}, reason => {
fn()
throw reason
})
}
/**
* done方法作为Promise链式调用的最后一步,用来向全局抛出没有被Promise内部捕获的错误,
* 并且不再返回一个Promise。一般用来结束一个Promise链。
* @param {*} fn
*/
MyPromise.prototype.done = function(fn) {
this.catch(reason => {
fn()
throw reason
})
}
/**
* Promise.all()接收一个包含多个Promise的数组,当所有Promise均为fulfilled状态时,
* 返回一个结果数组,数组中结果的顺序和传入的Pronise顺序一一对应。如果有一个Promise为
* rejected状态,则整个Promise.all为rejected。
* @param {*} promiseArr
*/
MyPromise.all = function(promiseArr) {
return new MyPromise((resolve, reject) => {
let result = []
promiseArr.forEach((promise, index) => {
promise.then(value => {
result[index] = value
if (result.length === promiseArr.length) {
resolve(result)
}
}, reject)
})
})
}
/**
* Promise.race()接收一个包含多个Promise的数组,当有一个Promise为fulfilled状态时,
* 整个大的Promise为onfulfilled,并执行onFulfilled回调函数。如果有一个Promise为rejected
* 状态,则整个Promise.race为rejected。
* @param {*} promiseArr
*/
MyPromise.race = function(promiseArr) {
return new Promise((resolve, reject) => {
promiseArr.forEach(promise => {
promise.then(value => {
resolve(value)
}, reject)
})
})
}
/**
* Promise.resolve用来生成一个fulfilled完成态的Promise,一般放在整个Promise链的开头,
* 用来开始一个Promise链。
* @param {*} value
*/
MyPromise.resolve = function(value) {
let promise = null
promise = new MyPromise((resolve, reject) => {
this.prototype.resolvePromise(promise, value, resolve, reject)
})
return promise
}
/**
* Promise.reject用来生成一个rejected失败态的Promise。
* @param {*} reason
*/
MyPromise.reject = function(reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
/**
* Promise.deferred可以用来延迟执行resolve和reject。
* 这样就可以在外部通过调用dfd.resolve()和dfd.reject()来决议该Promise。
*/
MyPromise.deferred = function() {
let dfd = {}
dfd.promise = new MyPromise((resolve, reject) => {
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
/**
* stop中返回一个永远不执行resolve或者reject的Promise,那么这个Promise永远处于
* pending状态,所以永远也不会向下执行then或catch了。这样我们就停止了一个Promise链。
* 但是这样会有一个缺点,就是链式调用后面的所有回调函数都无法被垃圾回收器回收。
*/
MyPromise.stop = function() {
return new MyPromise(function() {})
}
module.exports = MyPromise
test.js
let MyPromise = require('./MyPromise.js')
let promise1 = new MyPromise((resolve, reject) => {
console.log('aaa')
resolve(123)
})
async function fn() {
let result = await promise1.then()
console.log(result)
}
fn()
// let promise2 = new MyPromise((resolve, reject) => {
// console.log('bbb')
// setTimeout(() => {
// reject(222)
// console.log(222)
// }, 400);
// })
// let promise3 = new MyPromise((resolve, reject) => {
// console.log('ccc')
// setTimeout(() => {
// resolve(333)
// console.log(333)
// }, 500);
// })
// MyPromise.race([promise1, promise2, promise3]).then(value => {
// console.log('the value:', value)
// }, reason => {
// console.log('the reason:', reason)
// })
// MyPromise.reject(111).then(value => {
// console.log('value1', value)
// return new MyPromise((resolve, reject) => {
// resolve(222)
// })
// }).then(value => {
// console.log('value2:', value)
// }).catch(reason => {
// console.log('reason:', reason)
// })