Skip to content

Promise 原理解析

es5实现方案

js
// 参考: https://juejin.im/post/5aab286a6fb9a028d3752621#heading-3
// 三个状态,pending只能扭转成一个状态
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'

function Promise(executor) {
	console.log('-------------------Promise_es5-------------------')
    let self = this
	self.status = PENDING // 初始为pending
	self.data = undefined // 成功或失败的值
    self.callbacks = [] // 执行器中为异步时保存的回调
    function resolve(value) {
        if(self.status !== PENDING) return;
        self.status = RESOLVED
        self.data = value
        if(self.callbacks.length > 0) self.callbacks.forEach(fn => fn.onFulfiled(value))
    }
    function reject(reason) {
        if(self.status !== PENDING) return;
        self.status = REJECTED
        self.data = reason
		if(self.callbacks.length > 0) self.callbacks.forEach(fn => fn.onRejected(reason))
    }
    try{
        executor(resolve, reject) // 同步执行Promise内回调,捕获错误传给reject
    } catch(err) {
        reject(err)
    }
}

// 1、返回一个新的Promise
// 2、返回的Promise结果由onfulfilled或onRejected决定
Promise.prototype.then = function (onFulfiled, onRejected) {
	let self = this
	onFulfiled = typeof(onFulfiled) === 'function' ? onFulfiled : value => value // value为普通值,传啥进去,return啥出来,见行40(值的穿透)
	onRejected = typeof(onRejected) === 'function' ? onRejected : reason => {throw reason}
    return new Promise((resolve, reject) => {
		function handle(cb) {
			try {
				let res = cb(self.data)
				if(res instanceof Promise) {
					// res.then(value => resolve(value), reason => reject(reason))
					res.then(resolve, reject) // 简写
				}else{
					resolve(res) // 非Promise对象resolve res即可(上面已经调用过一次了)
				}
			} catch (err) {
				reject(err)
			}
		}
		if(self.status === RESOLVED) {
			handle(onFulfiled)
		}
		if(self.status === REJECTED) {
			handle(onRejected)
		}
        if(self.status === PENDING) { // 如果执行到.then的时候还没resovle或者reject则先保存回调
			self.callbacks.push({
				onFulfiled() {
					handle(onFulfiled)
				},
				onRejected() {
					handle(onRejected)
				}
			})
        }
    })
}

// 返回的不是一个新的Promise,只是一个上一个then放回的Promise,只是修改里面的内容
Promise.prototype.catch = function (onRejected) {
	return this.then(undefined, onRejected)
}

// 实现静态方法
Promise.resolve = function (value) {
	return new Promise((resolve, reject) => {
		if(value instanceof Promise){
			value.then(resolve, reject)
		}else {
			resolve(value)
		}
	})
}

Promise.reject = function (reason) {
	return new Promise((resolve, reject) => {
		reject(reason)
	})
}

Promise.all = function (promises) {
	if(!(promises instanceof Array)) throw new Error('传个数组,老铁')
	let valueArr = new Array(promises.length), // 与all中数组等长的数组
		resolveCount = 0;
	return new Promise((resolve, reject) => {
		promises.forEach((p, i) => {
			// Promise.resolve(p): p要包一层的原因是p有可能不是一个promise对象,于是包一层就好了,不用做多余的判断
			Promise.resolve(p).then(value => {
				// valueArr.push(value) // 不能用push,用push不能保证顺序
				valueArr[i] = value
				resolveCount++
				if(resolveCount === promises.length) resolve(valueArr)
			}, reason => {
				reject(reason)
			})
		})
	})
}

Promise.race = function (promises) {
	if(!(promises instanceof Array)) throw new Error('传个数组,老铁')
	return new Promise((resolve, reject) => {
		promises.forEach((p, i) => {
			// Promise.resolve(p): p要包一层的原因是p有可能不是一个promise对象,于是包一层就好了,不用做多余的判断
			Promise.resolve(p).then(value => {
				resolve(value) // 假如第一个成功的立即resolve
			}, reason => {
				reject(reason) // 假如第一个失败的立即reject
			})
		})
	})
}

// 自定义延时回调的方法
// value为resolve的值, time为延时执行的时间
Promise.resolveDelay = function (value, time) {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			if(value instanceof Promise) { // 判断一下是否是Promise实例,是则取其value值
				value.then(resolve, reject)
			}else{
				resolve(value) // 不是则直接resolve
			}
		}, time)
	})
}
Promise.rejectDelay = function (reason, time) {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
				reject(reason) // 延迟后返回一个失败的Promise实例
		}, time)
	})
}

// 实现一个promise的延迟对象 defer
// 此步是为了测试我们手写的Promsie符不符合Promsie/A+规范,如果没有defer的话,我们在测试过程中就会报一个TypeError: adapter.deferred is not a function.
Promise.defer = Promise.deferred = function(){
    let dfd = {};
    dfd.promise = new Promise((resolve, reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd;
}

// module.exports = Promise

es6实现方案

js
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTD = 'rejected'
export default class Promise{
    constructor(executor) {
		// console.log('-------------------Promise_es6-------------------')
        this.state = PENDING
        this.data = undefined
        this.callbacks = []
        let self = this
        function resolve(value) {
            if(self.state !== PENDING) return; // 状态只能改变一次,如果不是PENDING过渡过来直接return,reject同。
            self.state = RESOLVED
            self.data = value
            if(self.callbacks.length > 0) self.callbacks.forEach(fn => fn.onResolved())
        }
        function reject(reason) {
            if(self.state !== PENDING) return;
            self.state = REJECTD
            self.data = reason
            if(self.callbacks.length > 0) self.callbacks.forEach(fn => fn.onRejected())
        }
        try {
            executor(resolve, reject)
        } catch (error) {
            reject(error)
        }
    }
    then(onResolved, onRejected) {
		// console.log(typeof(onResolved) === 'function')
		// 如果两个参数不是函数,则会在内部被替换为 (x) => x,即原样返回 promise 最终结果的函数
		onResolved = typeof(onResolved) === 'function' ? onResolved : value => value // 普通值穿透
		onRejected = typeof(onRejected) === 'function' ? onRejected : reason => {throw reason} // 普通值穿透
		let self = this
		return new Promise((resolve, reject) => { // 1、then返回新的Promise对象,但是要注意它的返回值
			function handle(cb) {
				try {
					let res = cb(self.data) // 2、返回值
					if(res instanceof Promise) { // 3、如果返回的Promise对象,通过then获取其值
						// res.then(value => resolve(value), reason => reject(reason))
						res.then(resolve, reject) // 简写,同上
					}else { // 非Promise对象,直接resolve
						resolve(res)
					}
				} catch (error) {
					reject(error)
				}
			}
			if(self.state === RESOLVED) {
				// 模拟异步
				setTimeout(() => {
					handle(onResolved)
				})
			}
			if(self.state === REJECTD) {
				setTimeout(() => {
					handle(onRejected)
				})
			}
			if(self.state === PENDING) { // 如果这里还是PENDING,说明executor里面有异步操作,先把回调保存起来
				self.callbacks.push({
					onResolved() {
						handle(onResolved)
					},
					onRejected() {
						handle(onRejected)
					}
				})
			}
		})
	}
	catch(errCb) {
		return this.then(undefined, errCb)
	}
	// Promise静态方法的实现(返回的是Promise对象)
	static resolve(value) {
		return new Promise((resolve, reject) => {
			if(value instanceof Promise) {
				value.then(value => resolve(value), reason => reject(reason))
			}else {
				resolve(value)
			}
		})
	}
	static reject(reason) {
		return new Promise((resolve, reject) => {
			reject(reason)
		})
	}
	static all(promises) {
		let res = new Array(promises.length),
			count = 0
		return new Promise((resolve, reject) => {
			promises.forEach((p, i) => {
				// Promise.resolve(p):防止promises中存在非Promise值
				Promise.resolve(p).then(value => {
					res[i] = value
					// 注意一下下面两行代码,不要写到then外面去了!!!
					count++
					if(count === promises.length) resolve(res)
				}, reason => {
					reject(reason)
				})
			})
		})
	}
	static race(promises) {
		return new Promise((resolve, reject) => {
			promises.forEach(p => {
				Promise.resolve(p).then(value => {
					resolve(value) // 返回最快的那个即可
				}, reason => {
					reject(reason)
				})
			})
		})
	}
	// 自定义的静态方法:指定时间延迟执行
	static resolveDelay(value, time) {
		return new Promise((resolve, reject) => {
			setTimeout(() => {
				if(value instanceof Promise) {
					// value.then(resolve, reject)
					value.then(value => resolve(value), reason => reject(reason))
				}else {
					resolve(value)
				}
			}, time)
		})
	}
	static rejectDelay(reason, time) {
		return new Promise((resolve, reject) => {
			setTimeout(() => {
				reject(reason)
			}, time)
		})
	}

}

// 测试方法
Promise.defer = Promise.deferred = function(){
    let dfd = {};
    dfd.promise = new Promise((resolve, reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd;
}

// module.exports = Promise