JS 之 手打实现 Promise

195 阅读4分钟

「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」。

Promise

  • Promise 有三个状态, pending 等待态, reject 失败态, resolve 成功态
  • new Promise 时需要传递一个 executor 执行器,执行器会立即执行
  • 执行器中传递两个参数 resolve 成功函数,它调用的时候可以传递一个值,值可以是任何值. reject 失败函数,它调用时也可以传递一个值,值可以是任何值
  • 从初始等待态 pending 只可以向失败态 reject 或者成功态 resolve 转变且不能再更改
  • Promise 的每个实例都拥有一个 then 方法,这个方法传递两个参数,一个是成功的回调,另一个是失败的回调
  • 如果调用 then 时,发现已经成功,会让这个成功函数执行并且把成功的内容当做参数传递到 then 方法的成功回调中,反之就是失败回调中
  • Promise 中可以同一个实例多次调用 then 方法多次,如果状态是 pending 需要将函数存放起来,等状态确定后,在以此将对应函数执行(发布订阅)
  • 如果执行时出现异常,Promise 状态就会从 pending 变更为失败态 reject
        let p = new Promise((resolve, reject) => {
            resolve(1);
        })
        let p2 = new Promise((resolve, reject) => {
            reject(2);
        })
        p.then((value) => {
            console.log(value); // 1
        }, (reason) => {
            console.log('err', reason);
        });

        p.then((value) => {
            console.log(value); // 1
        }, (reason) => {
            console.log('err', reason);
        });

        p2.then((value) => {
            console.log(value)
        }, (reason) => {
            console.log('err', reason); // 2
        });


链式调用

  • 每次 Promise 执行 then 后都会返回一个新的 Promise
  • 如果 then 中返回的是一个结果,会把这个结果传递到下一次 then 中的成功回调
  • 如果 then 中出现异常,会走下一个 then 的失败回调并错误传递到失败回调中
  • catch 会捕获到没有捕获的异常

如果 then 方法返回的是一个 Promise 那么会等待这个 Promise 执行完决定返回的是成功态还是失败态 为什么要返回一个新的 Promise 而不是 this 是因为 Promise 的状态一但确定后就不能更改

		let p = new Promise((resolve, reject) => {
			resolve(1);
		})
		p.then(data => {
			console.log(data); // 1
			throw new Error('啥也不是');
		}).then(null, (err) => {
			console.log(err); // Error: 啥也不是
		})

Promise 实现

		function MyPromise(executor) {
			let self = this;
			self.status = 'pending'; // 初始状态
			self.value = undefined; // 成功回调传递值
			self.reason = undefined; // 失败回调传递值
			self.onResolved = []; // 成功事件池
			self.onRejected = []; // 失败事件池
			function resolve(value) {
				// 成功状态函数
				if (self.status === 'pending') {
					self.value = value;
					self.status = 'resolved';
					self.onResolved.forEach(fn => fn());
				}
			};
			function reject(reason) {
				// 失败状态函数
				if (self.status === 'pending') {
					self.reason = reason;
					self.status = 'rejected';
					self.onRejected.forEach(fn => fn());
				}
			};
			try {
				executor(resolve, reject);
			} catch (e) {
				// catch 会捕获到没有捕获的异常 一层语法糖
				reject(e);
			}
		}
		// 解析函数 判断then 链式调用之后的是否都是Promise
		function resolvePromise(promise2, x, resolve, reject) {
			if (promise2 === x) {
				return reject(new TypeError('循环引用'));
			}
			// 这个方法是处理所有 Promise 的实现
			let called; // 用来防止多次调用
			if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
				try {
					let then = x.then;
					if (typeof then === 'function') {
						// 让返回的这个 x 也就是返回的 Promise 执行
						// 用它的状态让promise2 成功或者失败
						then.call(x, (y) => {
							if (called) return;
							called = true;
							// 递归解析 如果resolve 是一个 Promise 就要不停的让resolve的结果进行处理
							resolvePromise(promise2, y, resolve, reject);
						}, (e) => {
							if (called) return;
							called = true;
							reject(e)
						});

					} else {
						resolve(x);
					}
				} catch (e) {
					if (called) return;
					called = true;
					reject(e);
				}
			} else {
				// x就是一个普通值 (就用这个值让返回的promise成功即可)
				resolve(x);
			}
		}
		MyPromise.prototype.then = function (onfulfilled, onRejected) {

			// 判断onfulfilled是否是函数 不是返回一个函数 因为是成功的回到要保持他的存在意义
			onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : val => val;
			// 判断onRejected是否是函数 不是直接返回报错信息 
			console.log(typeof onRejected);
			onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
			let self = this;
			// 这里需要判断 onfulfilled与onfulfilled执行结果和 promise2 的关系
			let promise2;
			promise2 = new MyPromise((resolve, reject) => {
				if (self.status === 'resolved') {
					setTimeout(() => {
						try {
							let x = onfulfilled(self.value); // 将resolve传递的参数在then的成功回调函数中
							resolvePromise(promise2, x, resolve, reject); // 解析x 和 promise2的关系
						} catch (e) {
							reject(e);
						}
					}, 0)
				};
				if (self.status === 'rejected') {
					setTimeout(() => {
						try {

							let x = onRejected(self.reason); // 将reject传递的参数在then的失败回调函数中
							resolvePromise(promise2, x, resolve, reject); // 解析x 和 promise2的关系
						} catch (e) {
							reject(e);
						}

					}, 0)
				};
				if (self.status === 'pending') {
					// 将 pending 状态 先放进 成功状态池中
					self.onResolved.push(function () {
						setTimeout(() => {
							try {
								let x = onfulfilled(self.value);
								resolvePromise(promise2, x, resolve, reject); // 解析x 和 promise2的关系
							} catch (e) { reject(e); }
						}, 0)
					});
					self.onRejected.push(function () {
						setTimeout(() => {
							try {
								let x = onRejected(self.reason);
								resolvePromise(promise2, x, resolve, reject); // 解析x 和 promise2的关系
							} catch (e) {
								reject(e);
							}
						}, 0)
					})
				}
			})
			return promise2
		}



		let a = new MyPromise((resolve, reject) => {
			// resolve('MyPromise 成功了吗');
			reject('MyPromise 失败了吗')
		});
		a.then((value) => {
			console.log(value);
		}, (e) => {
			console.log(e);
		})