skip to content
天真笔录

Promise学习笔记

/ 7 min read

Promise特点

  1. then的返回值
const promise = new Promise((resolve, reject) => {
	resolve("success");
});
// 普通值会转为Promise对象
promise.then((res) => {
	return "haha"; // Promise.resolve('hahaha')
});
// 返回Promise
promise.then((res) => {
	return new Promise((resolve, reject) => {
		resolve("success");
	});
});
// 返回thenable对象
promise.then((res) => {
	return {
		then(resolve, reject) {
			resolve("tianzhen");
		},
	};
});
  1. then和catch都会返回一个新的Promise

promise理解

  • 异步编程的一种解决方案,
  • JS原生对象
  • 解决了以前回调地狱
  • 改善了异步编程的困境
  • 回调函数和事件更强大

三种状态

  1. pending
  2. fulfilled
  3. rejected

    pending->fulfilled/rejected一旦转换无法更改

异常处理

  1. .then((success, error)), 弊端:只能捕获Promise主体异常,如果success里出现异常则无法捕获
  2. try...catch, 弊端:只能捕获同步代码异常
  3. .catch(),推荐使用catch捕获

链式调用

.then().then().catch() 每次调用都会返回一个新的Promise实例对象,所以可以.then()

实例API(原型)

  1. then
  2. catch
  3. finally

静态方法

  1. resolve
  2. reject
  3. all([]) 所有promisefulfilled
  4. race([]) 任一fulfilled、rejected
  5. any([]) 第一个fulfilled, es12/es2021: 拿到第一个resolve
  6. allSettled 都有结果(无论是resolve,reject)
  7. any 第一个resolve

其他

  • resolve()参数
  1. 参数是普通类型,返回值将自动转为promise
  2. 参数是promise,状态由promiseresolve、reject决定
  3. 参数是thenable对象,也会执行then方法

基础实现

const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class myPromise {
	constructor(executor) {
		this.status = "pending"; // 保存当前处于哪一状态
		this.reason = undefined; // 保存reject结果
		this.value = undefined; // 保存resolve结果

		const resolve = (value) => {
			console.log(value);
			this.value = value;
		};

		const reject = (reason) => {
			console.log(reason);
			this.reason = reason;
		};

		executor(resolve, reject);
	}
}

const p = new myPromise((resolve, reject) => {
	resolve("success");
	reject("fail");
	throw new Error("error");
});

问题:

  1. resolve和reject都执行了
  2. 最终status: rejected
  3. 无法捕获主体异常

添加状态不可逆

const resolve = (value) => {
	if (this.status === PENDING) {
		this.status = FULFILLED;
		console.log(value);
		this.value = value;
	}
};

const reject = (reason) => {
	if (this.status === PENDING) {
		this.status = REJECTED;
		console.log(reason);
		this.reason = reason;
	}
};

捕获主体异常

try {
	executor(resolve, reject);
} catch (error) {
	reject(error);
}

实现then

then(onFulfilled, onRejected) {
  if(this.status === FULFILLED) {
    onFulfilled(this.value)
  }
  if(this.status === REJECTED) {
    onFulfilled(this.reason)
  }
}

// 测试
p.then(res => {
  console.log(res) // success
})

问题:

  1. 无法处理主体异步问题
const p = new myPromise((resolve, reject) => {
	setTimeout(() => {
		resolve("timeout");
	}, 1000);
});
p.then((res) => {
	console.log("res", res); // 这里不会执行
});

解决异步问题

因为执行then的时候status的状态还是pending,所以就没办法执行onFulfilled, 可以先将then的回调先保存起来,在resolve或reject时再调用

constructor(executor) {
  this.fulfilledCallbacks = [] // then 可以多次调用,使用数组保存
  this.rejectedCallbacks = []
}
then(onFulfilled, onRejected) {
  if(this.status === PENDING) {
    onFulfilled && this.fulfilledCallbacks.push(onFulfilled)
    onRejected && this.rejectedCallbacks.push(onRejected)
  }
}
const resolve = (value) => {
  this.fulfilledCallbacks.forEach(cb => {
    cb(this.value)
  })
}
const reject = (reason) => {
  this.fulfilledCallbacks.forEach(cb => {
    cb(this.reason)
  })
}
  • 完整代码
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class myPromise {
	constructor(executor) {
		this.status = "pending"; // 保存当前处于哪一状态
		this.reason = undefined; // 保存reject结果
		this.value = undefined; // 保存resolve结果
		this.fulfilledCallbacks = [];
		this.rejectedCallbacks = [];

		const resolve = (value) => {
			if (this.status === PENDING) {
				this.status = FULFILLED;
				// console.log(value)
				this.value = value;

				this.fulfilledCallbacks.forEach((cb) => {
					cb(this.value);
				});
			}
		};

		const reject = (reason) => {
			if (this.status === PENDING) {
				this.status = REJECTED;
				// console.log(reason)
				this.reason = reason;

				this.rejectedCallbacks.forEach((cb) => {
					cb(this.reason);
				});
			}
		};

		try {
			executor(resolve, reject);
		} catch (error) {
			reject(error);
		}
	}

	then(onFulfilled, onRejected) {
		if (this.status === FULFILLED) {
			onFulfilled(this.value);
		}
		if (this.status === REJECTED) {
			onFulfilled(this.reason);
		}
		if (this.status === PENDING) {
			onFulfilled && this.fulfilledCallbacks.push(onFulfilled);
			onRejected && this.rejectedCallbacks.push(onRejected);
		}
	}
}

const p = new myPromise((resolve, reject) => {
	// resolve('success')
	// reject('fail')
	// throw new Error('eeeeee')
	setTimeout(() => {
		resolve("timeout");
	}, 1000);
});
p.then((res) => {
	console.log("res1==========================", res);
});
p.then((res) => {
	console.log("res2==========================", res);
});

实现链式调用

返回一个新的promise实例

then(onFulfilled, onRejected) {
  const thenPromise = new myPromise((resolve, reject) => {
    if(this.status === FULFILLED) {
      try {
        const value = onFulfilled(this.value)
        resolve(value)
      } catch (error) {
        reject(error)
      }
    }
    if(this.status === REJECTED) {
      try {
        const value = onRejected(this.reason)
        resolve(value)
      } catch (error) {
        reject(error)
      }
    }
    if(this.status === PENDING) {
      onFulfilled && this.fulfilledCallbacks.push(() => {
        try {
          const value = onFulfilled(this.value)
          resolve(value)
        } catch (error) {
          reject(error)
        }
      })
      onRejected && this.rejectedCallbacks.push(() => {
        try {
          const value = onRejected(this.reason)
          resolve(value)
        } catch (error) {
          reject(value)
        }
      })
    }
  })

  return thenPromise
}
  • 注意 之前的onFulfilled && this.fulfilledCallbacks.push(onFulfilled)要改成下面这样
onFulfilled &&
	this.fulfilledCallbacks.push(() => {
		try {
			const value = onFulfilled(this.value);
			resolve(value);
		} catch (error) {
			reject(error);
		}
	});

因为之前是直接pushonFulfilled,无法拿到onFulfilled的结果

添加catch

catch可以看做是then只传了第二个参数

catch(onRejected) {
  this.then(undefined, onRejected)
}
  • 完整代码
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

// 统一处理异常
const catchFn = (fn, value, resolve, reject) => {
	try {
		const result = fn(value);
		resolve(result);
	} catch (error) {
		reject(error);
	}
};

class myPromise {
	constructor(executor) {
		this.status = "pending"; // 保存当前处于哪一状态
		this.value = undefined; // 保存resolve结果
		this.reason = undefined; // 保存reject结果
		this.fulfilledCallbacks = [];
		this.rejectedCallbacks = [];

		const resolve = (value) => {
			if (this.status === PENDING) {
				this.status = FULFILLED;
				// console.log(value)
				this.value = value;

				while (this.fulfilledCallbacks.length) {
					this.fulfilledCallbacks.shift()(this.value);
				}
			}
		};

		const reject = (reason) => {
			if (this.status === PENDING) {
				this.status = REJECTED;
				// console.log(reason)
				this.reason = reason;

				while (this.rejectedCallbacks.length) {
					this.rejectedCallbacks.shift()(this.reason);
				}
			}
		};

		try {
			executor(resolve, reject);
		} catch (error) {
			reject(error);
		}
	}

	then(onFulfilled, onRejected) {
		onRejected =
			typeof onRejected === "function"
				? onRejected
				: (reason) => {
						throw reason;
				  };

		const thenPromise = new myPromise((resolve, reject) => {
			if (this.status === FULFILLED) {
				catchFn(onFulfilled, this.value, resolve, reject);
			}
			if (this.status === REJECTED) {
				catchFn(onRejected, this.reason, resolve, reject);
			}
			if (this.status === PENDING) {
				onFulfilled &&
					this.fulfilledCallbacks.push(() => {
						catchFn(onFulfilled, this.value, resolve, reject);
					});
				onRejected &&
					this.rejectedCallbacks.push(() => {
						catchFn(onRejected, this.reason, resolve, reject);
					});
			}
		});

		return thenPromise;
	}

	catch(onRejected) {
		this.then(undefined, onRejected);
	}
}

真题

返回非promise对象

返回非promise对象都会转为promise

(function () {
	Promise.resolve()
		.then(() => {
			return new Error("error");
		})
		.then((res) => {
			console.log("then: ", res);
		})
		.catch((err) => {
			console.log("catch: ", err);
		});
	// then: Error: error
})();
  • 尽管是抛出了异常,其实 return new Error(‘error’) === Promise.resolve(new Error(‘error’))

值穿透

Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log);
  • then catch的参数期望是函数,传入非函数会发生值穿透
  • 第一个then和第二个then的参数都不是函数,所以发生了值穿透,1直接进入了最后一个then