手写promise2

88 阅读8分钟

书接上文,实现静态方法

实现promise.all

该方法时静态方法,接受一个数组,根据数组顺序去返回一个结果

该方法返回一个promise对象可以链式调用then

如果all方法中有任何一个元素执行失败,那么all最终结果就是失败

const p1 = new Promise((resolve, reject) => {resolve('p1')})
const p2 = new Promise((resolve, reject) => {resolve('p2')})
Promise.all([1,'a', p1, 'b', p2]).then(response => {
	// response --- [1,'a', 'p1', 'b', 'p2'] p1 和 p2 是执行结果
})

下面我们基于 Mypromise.all

Class Mypromise{
	constructor() {}
	// 静态方法用static 声明
	// all接受一个数组array;
	static all(array) {
		// 循环遍历数组每一项
		// 判断数组的每个元素,如果当前元素是普通值,应该传递出去
		// 如果是promise 对象应该得到promise对象执行结果
		// - 声明一个result 用来当作响应数据
		let result = [];
	
		for(var i = 0; i< array.length; i++) {
			if (array[i] instanceof Mypromise) {
				// promise对象
				// 执行结果是成功 用resolve函数响应出去
				// 执行结果是失败 用reject函数发送失败小心
				array[i].then(response=> {}, errmessage=> {})
			} else {
				// 普通值
				result[i] = array[i]
			}
			// 如果走到最后说明result中的值都是成功的响应
			// 直接resolve(result)
			resolve(result)
		}
		return new Mypromise((resolve, reject) => { })// all 返回了一个promise对象
		}
	}
}

因此循环要写在 Mypromise的执行器当中

let result = [];
return new Mypromise((resolve, reject) => { })// all 返回了一个promise对象
		// 循环遍历数组每一项
		// 判断数组的每个元素,如果当前元素是普通值,应该传递出去
		// 如果是promise 对象应该得到promise对象执行结果
		// - 声明一个result 用来当作响应数据
		
		for(var i = 0; i< array.length; i++) {
			if (array[i] instanceof Mypromise) {
				// promise对象
				// 执行结果是成功 用resolve函数响应出去
				// 执行结果是失败 用reject函数发送失败小心
				array[i].then(response=> {
						result[i] = response
				}, errmessage=> {
						// 调用reject
						reject(errmessage)
				})
			} else {
				// 普通值
				result[i] = array[i]
			}
			// 如果走到最后说明result中的值都是成功的响应
			// 直接resolve(result)
			resolve(result)
		}
}

const p1 = new Mypromise((resolve, reject) => {
	// throw new Error('executor错误')
	resolve('p1')
})

const p2 = new Mypromise((resolve, reject) => {
	// throw new Error('executor错误')
	resolve('p2')
})	
Mypromise.all([1,2,p1,'1-',p2, 0]).then(response => {
	console.log(response)  
})
// 打印结果是什么??
// 

emm // [1, 2, 空, '1-', 空, 0, 'p2'] 数组长度也错了

因为for循环用var 声明了变量, 并且then中使用了setTimeout。 循环完成后i = 6. 由于setTimout, 因此会有result由 // [1, 2, 空, '1-', 空, 0, 'p1'] ====》变成 [1, 2, 空, '1-', 空, 0, 'p2']的过程

// 这里用let声明i即可
for(let i = 0; i< array.length; i++) {
			if (array[i] instanceof Mypromise) {
				// promise对象
				// 执行结果是成功 用resolve函数响应出去
				// 执行结果是失败 用reject函数发送失败小心
				array[i].then(response=> {
						result[i] = response
				}, errmessage=> {
						// 调用reject
						reject(errmessage)
				})
			} else {
				// 普通值
				result[i] = array[i]
			}
// 打印结果
//[1, 2, 'p1', '1-', 'p2', 0]

如果p1是异步的操作呢


const p1 = new Mypromise((resolve, reject) => {
	// throw new Error('executor错误')
	setTimeout(() => resolve('p1'), 0) // 0s后返回执行resolve p1
})

const p2 = new Mypromise((resolve, reject) => {
	// throw new Error('executor错误')
	resolve('p2')
})
Mypromise.all([1,2,p1,'1-',p2, 0]).then(response => {
	console.log(response)  
})

//  [1, 2, 空, '1-', 'p2', 0] 
// 分析下 
// all 执行时 p1时pendding状态 p2时fulfille状态
// then执行是 由于状态问题 p1是异步完成后才resolve后执行this.successCallback p2是successFn中执行
// for循环是同步的 因此array[i] 如果时p1 还没执行完就 执行了resolve(result); 所以我们应该确保循环i当前有值,才进行resolve

// 定义一个模块级变量
		let index = 0;
		return new Mypromise((resolve, reject) => {
			// 循环遍历数组每一项
			// 判断数组的每个元素,如果当前元素是普通值,应该传递出去
			// 如果是promise 对象应该得到promise对象执行结果

					array[i].then(response=> {

						result[i] = response
						// 每次添加到result后index++
						index++
						// 如果index最后和array.lengh相同
						index===array.length && resolve(result)
					}
					// 普通值
					result[i] = array[i]
					// 每次添加到result后
					index++
				}	
			}
			// 如果走到最后说明result中的值都是成功的响应
			// 直接resolve(result)
			// 如果index最后和array.lengh相同
			index===array.length && resolve(result)
	}

// 
Mypromise.all([1,2,p1,'1-',p2, 0]).then(response => {
	console.log(response)  
})

//  [1, 2, 'p1', '1-', 'p2', 0]

Promise.resolve

Promise.resolve返回一个promise,并且将给定的值传递给下一个then进行链式调用

如给的值是一个promise 将promisef返回就行

static resolve(value) {
		if (value instanceof Mypromise) value;
		return new Mypromise((resolve) => resolve(value))
}

Mypromise.resolve('1').then(val => console.log(val)) // '1'
Mypromise.resolve(p1).then(val => console.log(val)) // 'p1'

finally

finally 回调会被执行依次, 然后可以链式调用then

finally方法属于实例方法

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

let p1 = new Promise((resolve, reject) => {
	resolve('hello')
})
p1.finally(() => {
	console.log('执行回调')
}).then(res => {
	console.log(res) // 拿到p1的结果去then调用
})

------

finally(callback) {
		// 通过then知道promise的状态
		// then的成功回调和失败回调都要执行一次callback
		// finally方法可以链式调用说明返回了;而then方法也是返回了promise 所以return this.then就好
		return this.then((response)=> {
			callback()
			return response // response就是当前this promise当前的响应
		}, (errmessage)=> {
			callback()
			// 如果失败就抛出errerrmessage
			throw errmessage
		})
}
const p2 = new Mypromise((resolve, reject) => {
	// throw new Error('executor错误')
	reject('p2失败')
})
p2.finally(() => {
	console.log('finally') // finally
}).then(response => {
	console.log(response)
}, errmessage => {
	console.log(errmessage) // p2失败
})

在finally中可以进行return 一个结果,如果return的是一个promise 会等该promise结果完成后then执行then

const p1 = new Mypromise((resolve, reject) => {
	// throw new Error('executor错误')
	setTimeout(() => {
		console.log('p1执行')
		resolve()
	}, 100) // 0s后返回执行resolve p1
})

const p2 = new Mypromise((resolve, reject) => {
	// throw new Error('executor错误')
	reject('p2失败')
})
p2.finally(() => {
	console.log('finally')
	return p1 //执行p1
}).then(response => {
	console.log(response) 
}, errmessage => {
	console.log(errmessage) // 失败
})


// 
finally(callback) {

		return this.then((response)=> {
			// 通过promise.resolve传入callback 实际上 相当于 返回的是p1.then() 去执行p1之后再去用p2执行结果去then
			return Mypromise.resolve(callback()).then(() => response)
			// callback()
			// return response // response就是当前this promise当前的响应
		}, (errmessage)=> {
			// 同理
			return Mypromise.resolve(callback()).then(() => {throw errmessage})
			// callback()
			// // 如果失败就抛出errerrmessage
			// throw errmessage
		})
}

catch 错误捕获

catch(failureCallback) {
		// 调用then 成功回调传uundefined
		// 失败回调就是callback 调用catch时实际上就是调用then中的失败回调
		return this.then(undefined, failureCallback)
}

const p2 = new Mypromise((resolve, reject) => {
	// throw new Error('executor错误')
	reject('p2')
})
p2.then((res) => {
	console.log('res')
}).catch(res => {
    console.log(res)
})
// 打印 TypeError: failureFn is not a function

// 分析'P2'才对
p2是失败的状态, 当执行到then中缺没有失败回调。那么自然就发生了错误
还记

p2是失败状态rejected, 当执行then方法, 里面没有失败回调,只有成功回调。自然发生了错误

还记得第1篇中的then穿透吗我们当时给成功回调设置了默认值

对于失败回调呢

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

successFn = successFn ? successFn : value => value // 补参如果有参数就用 如果没有参数就是一个函数
failureFn = failureFn ? failureFn : value => {throw value} // 如果没有失败回调那么就 throw reject的消息
p2.then((res) => {
	console.log('res')
},
	value => {throw value}  // 相当与添加了一个错误信息 抛出一一个错误。被错误处理捕获到reject()
	
).catch(res => { // 到这里then成功回调是null, 失败回调时 res=> {log(res)}
    console.log(res)  
})

下面时所有代码

// 首先设置三种状态常量
const PENDDING = 'pendding';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected'
class Mypromise {
	constructor(executor) {
		// new promise是会立即执行执行器,并且接受两个参数, resolve函数和reject函数
		// 执行器执行时发生了错误用try cathch去捕获执行器执行
		try {
			executor(this.resolve, this.reject)
			
		} catch (e) {
			// 如果有错误直接执行reject
			this.reject(e)
		}
		
	}
	status = PENDDING; 
    response = undefined // 定义一个成功的响应值
    errmessage = undefined // 失败的信息
    // 首先我们用属性succcessCallback存储successFn 和 failureCallback存储failureFn
    succcessCallback = [];
    failureCallback = [];
	// resolve是一个函数, 参数是响应值 
    resolve = (response) => { 
        if(this.status !== PENDDING ) return
    	this.status = FULFILLED; 
    	this.response = response; // 缓存成功消息
        // 当异步操作2s后执行到resolve的时候 如果succcessCallback 存在那么执行succcessCallback 
    	//this.succcessCallback && this.succcessCallback(this.response)
        while (this.succcessCallback.length) {
            this.succcessCallback.shift()()
        }
    } 
    // reject也是一个函数, 参数是错误消息 
    reject= (errmessage) => { 
        if(this.status !== PENDDING ) return
    	this.status = REJECTED; 
    	this.errmessage = errmessage // 缓存失败信息
        // 当异步操作2s后执行到reject的时候 如果failureCallback 存在那么执行failureCallback 
    	//this.failureCallback && this.failureCallback (this.errmessage )
        while (this.failureCallback.length) {
            this.failureCallback.shift()()
        }
    } 
    then = (successFn, failureFn) => { 
		successFn = successFn ? successFn : value => value // 补参如果有参数就用 如果没有参数就是一个函数
        failureFn = failureFn ? failureFn : value => {throw value}
        // 获取到promise
        let pr = new Mypromise((resolve, reject) => {
            // 当前状态成功了执行successFn 
	    	// 当前状态失败了执行 failureFn 
	    	if(this.status === FULFILLED) {
				// 加入异步代码让它在pr生成后去用pr
				setTimeout(() => {
					// then中发生了错误 也用try catch捕获
					try {
						let res = successFn(this.response) // 执行成功的回调 参数是成功的响应数据
						resolvePromise(pr, res, resolve, reject) // 处理成功时结果
					} catch(e) {
						reject(e)
					}
				}, 0)
		        
	    		
	        } else if (this.status === REJECTED) {
				setTimeout(() => {
					// then中发生了错误 也用try catch捕获
					try {
						let res = failureFn(this.errmessage) // 执行失败的回调 参数是失败的信息
                        resolvePromise(pr, res, resolve, reject) // 处理失败时结果
					} catch(e) {
						reject(e)
					}
				}, 0)
			} else {
            // 如果是pendding状态我们首先储存succcessCallback  和 failureCallback 
    		// this.succcessCallback.push(successFn);
    		// this.failureCallback.push(failureFn);
			// 这里以前我们是通过push的方法存储回调 如果then中的异步,我们就要push 一个函数了。
				this.succcessCallback.push(() => {
						// 如果是成功去执行成功的代码
					setTimeout(() => {
						// then中发生了错误 也用try catch捕获
						try {
							let res = successFn(this.response) // 执行成功的回调 参数是成功的响应数据
							resolvePromise(pr, res, resolve, reject) // 处理成功时结果
						} catch(e) {
							reject(e)
						}
					}, 0)
					
				})
				this.failureCallback.push(() => {
					setTimeout(() => {
						// then中发生了错误 也用try catch捕获
						try {
							let res = failureFn(this.errmessage) // 执行失败的回调 参数是失败的信息
							resolvePromise(pr, res, resolve, reject) // 处理失败时结果
						} catch(e) {
							reject(e)
						}
					}, 0)
					
				});
	
	        }
	    })
    	
        return pr; // 返回一个promise
    }
    
    finally(callback) {
        return this.then((response) => {
            return Mypromise.resolve(callback()).then(() => response)
            // callback()
            // return response
        }, (errmessage) => {
            return Mypromise.resolve(callback()).then(() => {throw errmessage})
        })
    }
    catch(failCallback) {
        return this.then(undefined, failCallback)
    }
    // all接受一个数组array;
	static all(array) {
		// 循环遍历数组每一项
		// 判断数组的每个元素,如果当前元素是普通值,应该传递出去
		// 如果是promise 对象应该得到promise对象执行结果
		// - 声明一个result 用来当作响应数据
		let result = [];
        let index = 0
		
        // all 返回了一个promise对象
		return new Mypromise((resolve, reject) => { 
            for(let i = 0; i< array.length; i++) {
                if (array[i] instanceof Mypromise) {
                    // promise对象
                    // 执行结果是成功 用resolve函数响应出去
                    // 执行结果是失败 用reject函数发送失败小心
                    array[i].then(response=> {
                        result[i] = response
                        // 每次添加到result后index++
						index++
						// 如果index最后和array.lengh相同
						index===array.length && resolve(result)
                    }, errmessage=> {
                        reject(errmessage)
                    })
                } else {
                    // 普通值
                    result[i] = array[i]
                    index++
                }
                // 如果走到最后说明result中的值都是成功的响应
                // 直接resolve(result)
                index === array.leng && resolve(result)
            }


        })
	}

    static resolve(value) {
        if (value instanceof Mypromise) value;
        return new Mypromise((resolve, reject) => {resolve(value)})
    }
}
// res是successFn执行的结果, resolve是成功的回调, reject是结束的回调

function resolvePromise(returnP, res, resolve, reject) {
	console.log(res)
    if (returnP === res) {
		// 如果回调的promise 和 then中要返回的promise是同一个对象那么就发生了 循环调用。 直接return 阻止代码继续向下执行
		return reject(new TypeError ('Chaining cycle detected for promise #<Promise>'))
	}
    if (res instanceof Mypromise) {
        // 执行结果是一个promise
        // 调用then方法拿到执行结果如果成功执行resolve
        // 失败就调用reject
        res.then(value => resolve(value), err => reject(err))
    } else {
        // 普通值直接调用resolve方法
        resolve(res)
    }
}


const p2 = new Mypromise((resolve, reject) => {
	// throw new Error('executor错误')
	reject('p2')
})
p2.then((res) => {
	console.log('res')
}).catch(res => {
    console.log(res)
})