js手写promise(then(),catch(),all(),race())

Promise作用

所谓Promise,中文意思是期限,承诺的意思,就是使用一个对象来传递一个未来将要发生的事(promise),而到了那时(then),再来查看成功还是失败再来绝对将要执行的操作。(onResolve,onReject)。
博主一年前曾粗略地学习过promise地使用与实现,但当时理解较为浅薄。冷饭重炒,希望能发现一些新的东西。希望读者能够加以批评指正。
博主这次希望以一个循序渐进的过程(前提是熟悉promise的使用)来搭建这次代码实现;若只需代码,则直接移步第五章。

1. 框架搭建

(1) Promise状态值PromiseState(初始为pengding,可利用Promise中的resolve与reject来修改该值);Promise中的返回结果值PromiseResult;
(2) 传入构造函数中的执行器函数excutor;
(3) resolve()函数与reject()函数;
(4) 因需要创建函数resolve()与reject(),其中的this指向会改变,需要保留外层的this;
(5) 创建原型上的then()方法供Promise实例进行调用。

因此有如下代码:

function MyPromise(excutor) {
	let self = this 					// 保留外层this
	self.PromiseState = 'pending'		// 指定初始创建时的状态值
	self.PromiseResult = null			// 初始化返回值
	function resolve(data) {			// 定义resolve与reject
	}
	function reject(data) {
	}
	excutor(resolve,reject) 			// 执行执行器函数
}

MyPromise.prototype.then = function(onResolved,onRejected) {
										// then()中一般情况下会传入两个回调
}

2. resolve()与reject()的初步实现

(1) resolve()与reject()的作用是修改实例对象中的状态值(PromiseState)与返回值(PromiseResult);
(2) resolve()的作用是修改状态为'fulfilled'或'resolved',这里以’fulfilled‘为准,修改结果值为传入的参数值;
(3) reject()的作用是修改状态为'rejected',修改结果值为传入的参数值;
(4) 需要注意的是,在Promise传入的执行器函数中,状态值只能修改一次。
(5) resolve()中的参数值若为非Promise实例对象,则按原样执行,若为Promise实例对象,则执行then()方法并返回。

因此代码变为:

function MyPromise(excutor) {
	let self = this 					// 保留外层this
	self.PromiseState = 'pending'		// 指定初始创建时的状态值
	self.PromiseResult = null			// 初始化返回值
	function resolve(data) {			// 定义resolve与reject
		if(data instanceof MyPromise) {	// 若为MyPromise实例,则执行then()再返回
			return data.then(resolve,reject)
		}
		if(self.PromiseState !== 'pending') return;			//若不为pending则直接返回,防止多次修改
		self.PromiseState = 'fulfilled'	// 修改状态值
		self.PromiseResult = data		// 修改结果值
	}
	function reject(data) {
		if(self.PromiseState !== 'pending') return;			
		self.PromiseState = 'rejected'	
		self.PromiseResult = data		
	}
	excutor(resolve,reject) 			// 执行执行器函数
}

MyPromise.prototype.then = function(onResolved,onRejected) {
										// then()中一般情况下会传入两个回调
}

3. 异常throw处理

原生的Promise中包含throw(抛出错误的异常处理),效果等同于reject()使用try {} catch(e) {}
function MyPromise(excutor) {
	let self = this 					// 保留外层this
	self.PromiseState = 'pending'		// 指定初始创建时的状态值
	self.PromiseResult = null			// 初始化返回值
	function resolve(data) {			// 定义resolve与reject
		if(data instanceof MyPromise) {	// 若为MyPromise实例,则执行then()再返回
			return data.then(resolve,reject)
		}
		if(self.PromiseState !== 'pending') return;			//若不为pending则直接返回,防止多次修改
		self.PromiseState = 'fulfilled'	// 修改状态值
		self.PromiseResult = data		// 修改结果值
	}
	function reject(data) {
		if(self.PromiseState !== 'pending') return;			
		self.PromiseState = 'rejected'	
		self.PromiseResult = data		
	}
	try {
		excutor(resolve,reject) 			// 执行执行器函数
	} catch(e) {
		reject(e)
	}
}

MyPromise.prototype.then = function(onResolved,onRejected) {
										// then()中一般情况下会传入两个回调
}

4. then()方法的实现(resolve()与reject()的完善)

(1) then()方法存在一个返回值为Promise的实例对象;
(2) then()方法存在两个回调,第一个为成功之后执行的操作,第二个为失败之后执行的操;
(3) then()方法两个回调中都含有参数,其实这个值是创建Promise实例执行完后的结果也就是PromiseResult值。
(4) 若在new 方法中存在延时调用,then()方法会先于延时执行完执行,但then()方法中的回调会后于延时执行完,PromiseResult
结果传递完成之后再执行。因此需要在构造函数中定义回调(此时回调可能不止一个,因此回调类型应该为数组),当状态为	'pending',(无延时时then()在执行执行器后执行,状态早就变了;因此状态为pending说明执行器中存在延时调用,这里可能有点绕,需要琢磨一下,反正需要明确的就是then()的执行时机)在执行then()时传入实例对象的回调数组属性中,并在执行resolve()和reject()修改状态后遍历实例对象上的回调数组属性并执行。
(5) then()方法存在延时调用,需要加上延时器。
(6) then中两个回调为可选值,可传可不传。
(7) then()中回调的返回值若为非Promise实例类型,则调用resolve(),若为Promise实例,则调用then来查看状态值与结果值通过resolve()与reject()来修改要返回的Promise实例的状态与结果。

于是代码变成:

function MyPromise(excutor) {
	let self = this 					// 保留外层this
	self.PromiseState = 'pending'		// 指定初始创建时的状态值
	self.PromiseResult = null			// 初始化返回值
	self.callbacks = []					// then()中的回调
	setTimeout(() => {				// 遍历callbacks,then()中回调延时执行
        	self.callbacks.forEach(item => {
         		item.onResolved(data)
			})
    	});
	}
	function resolve(data) {			// 定义resolve与reject
		if(data instanceof MyPromise) {	// 若为MyPromise实例,则执行then()再返回
			return data.then(resolve,reject)
		}
		if(self.PromiseState !== 'pending') return;			//若不为pending则直接返回,防止多次修改
		self.PromiseState = 'fulfilled'	// 修改状态值
		self.PromiseResult = data		// 修改结果值
		setTimeout(() => {				// 遍历callbacks,then()中回调延时执行
        	self.callbacks.forEach(item => {
         		item.onResolved(data)
			})
    	});
	}
	function reject(data) {
		if(self.PromiseState !== 'pending') return;			
		self.PromiseState = 'rejected'	
		self.PromiseResult = data		
		setTimeout(() => {				// 遍历callbacks,then()中回调延时执行
        	self.callbacks.forEach(item => {
         		item.onResolved(data)
			})
    	});
	}
	try {
		excutor(resolve,reject) 			// 执行执行器函数
	} catch(e) {
		reject(e)
	}
}

MyPromise.prototype.then = function(onResolved,onRejected) {
										// then()中一般情况下会传入两个回调
	let self = this						// 保存外层this,防止返回MyPromise实例中this指向改变
	if(typeof onResolved !== 'function') {
		onResolved = value => value		// 若未传成功回调,则执行默认回调
	}
	if(typeof onRejected !== 'function') {
		onRejected = reason => {
			throw reason				// 若为传失败回调,则执行默认回调
		}
	}
	return new MyPromise((resolve,reject) => {	// 封装相同代码;检验回调返回值
		function callback(type) {
            try {
                let result = type(self.PromiseResult)
                if (result instanceof MyPromise) {		// 若为MyPromise
                    result.then(v => {
                        resolve(v)			// 通过回调的返回值执行then()后的状态与结果来修改返回的实例对象的返回值与结果
                    }, r => {
                        reject(r)
                    })
                } else {				// 若不为MyPromise实例,直接执行resolve来修改状态与返回值
                    resolve(result)
                }
            } catch (e) {
                reject(e)
            }
        }
        if (this.PromiseState === 'fulfilled') {
            setTimeout(() => {
                callback(onResolved)
            });
        }
        if (this.PromiseState === 'rejected') {
            setTimeout(() => {
                callback(onRejected)			// 延时调用
            });
        }
        // 判断pending状态
        if (this.PromiseState === 'pending') {	// 执行器函数中存在回调,则将回调存入callbacks属性
            this.callbacks.push({
                onResolved: function () {
                    callback(onResolved)
                },
                onRejected: function () {
                    callback(onRejected)
                }
            })
        }
	})
}

5.完善Promise() (完善Promise函数的方法)

其实到这里还没有结束,因为Promise自己还有resolve()方法与reject()方法。这里与实例中的其实差不多,直接上代码:

```javascript
function MyPromise(excutor) {
	let self = this 					// 保留外层this
	self.PromiseState = 'pending'		// 指定初始创建时的状态值
	self.PromiseResult = null			// 初始化返回值
	self.callbacks = []					// then()中的回调
	setTimeout(() => {				// 遍历callbacks,then()中回调延时执行
        	self.callbacks.forEach(item => {
         		item.onResolved(data)
			})
    	});
	}
	function resolve(data) {			// 定义resolve与reject
		if(data instanceof MyPromise) {	// 若为MyPromise实例,则执行then()再返回
			return data.then(resolve,reject)
		}
		if(self.PromiseState !== 'pending') return;			//若不为pending则直接返回,防止多次修改
		self.PromiseState = 'fulfilled'	// 修改状态值
		self.PromiseResult = data		// 修改结果值
		setTimeout(() => {				// 遍历callbacks,then()中回调延时执行
        	self.callbacks.forEach(item => {
         		item.onResolved(data)
			})
    	});
	}
	function reject(data) {
		if(self.PromiseState !== 'pending') return;			
		self.PromiseState = 'rejected'	
		self.PromiseResult = data		
		setTimeout(() => {				// 遍历callbacks,then()中回调延时执行
        	self.callbacks.forEach(item => {
         		item.onResolved(data)
			})
    	});
	}
	try {
		excutor(resolve,reject) 			// 执行执行器函数
	} catch(e) {
		reject(e)
	}
}

MyPromise.prototype.then = function(onResolved,onRejected) {
										// then()中一般情况下会传入两个回调
	let self = this						// 保存外层this,防止返回MyPromise实例中this指向改变
	if(typeof onResolved !== 'function') {
		onResolved = value => value		// 若未传成功回调,则执行默认回调
	}
	if(typeof onRejected !== 'function') {
		onRejected = reason => {
			throw reason				// 若为传失败回调,则执行默认回调
		}
	}
	return new MyPromise((resolve,reject) => {	// 封装相同代码;检验回调返回值
		function callback(type) {
            try {
                let result = type(self.PromiseResult)
                if (result instanceof MyPromise) {		// 若为MyPromise
                    result.then(v => {
                        resolve(v)			// 通过回调的返回值执行then()后的状态与结果来修改返回的实例对象的返回值与结果
                    }, r => {
                        reject(r)
                    })
                } else {				// 若不为MyPromise实例,直接执行resolve来修改状态与返回值
                    resolve(result)
                }
            } catch (e) {
                reject(e)
            }
        }
        if (this.PromiseState === 'fulfilled') {
            setTimeout(() => {
                callback(onResolved)
            });
        }
        if (this.PromiseState === 'rejected') {
            setTimeout(() => {
                callback(onRejected)			// 延时调用
            });
        }
        // 判断pending状态
        if (this.PromiseState === 'pending') {	// 执行器函数中存在回调,则将回调存入callbacks属性
            this.callbacks.push({
                onResolved: function () {
                    callback(onResolved)
                },
                onRejected: function () {
                    callback(onRejected)
                }
            })
        }
	})
}
MyPromise.resolve = function (value) {
    return new MyPromise((resolve, reject) => {
        if (value instanceof MyPromise) {
            value.then(v => {
                resolve(v)
            }, r => {
                reject(r)
            })
        } else {
            resolve(value)
        }
    })
}

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

.catch()方法的完善

其实就是调用失败的回调,也就是调用then()方法第一个参数不传。只传第二个参数。

MyPromise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected)
}

.all()方法的完善

.all()方法的执行就是传入一个promise数组,若全为成功回调,则返回的状态值为成功,同时结果变为成功结果的数组,但传入的顺序不能变化。若存在失败,则返回第一个失败回调的状态与结果。
代码如下:

MyPromise.all = function (promises) {
    return new MyPromise((resolve, reject) => {
        let count = 0		
        let arr = []		// 接收结果
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(v => {
                arr[i] = promises[i]				// 这里不能用push()推入数组的原因是若存在延时调用,执行完成顺序与传入顺序可能不同
                count++
                if (count === promises.length) {
                    resolve(arr)
                }
            }, r => {
                reject(r)
            })
        }
    })
}

.race()方法的完善

.race()方法就是传入一个promise数组,输出最先执行完成的promise对象的状态与结果

MyPromise.race = function (promises) {
    return new MyPromise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(v => {
                resolve(v)
            }, r => {
                reject(r)
            })
        }
    })
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值