Skip to content
On this page

什么是 Promise?

Promise是异步编程的一种解决方案:从语法上讲,Promise是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。Promise有三种状态:pending(等待态)fulfiled(成功态)rejected(失败态);状态一旦改变,就不会再变。创造Promise实例后,它会立即执行。

Promise/A+ 规范

详细介绍了该then方法的行为,提供了可互操作的基础

所有Promises/A+兼容的Promise实现都可以依靠该基础来提供

因此,该规范应被认为是非常稳定的。尽管Promises/A+组织有时会通过向后兼容的微小更改来修订此规范,以解决新发现的极端情况,但只有经过仔细考虑,讨论和测试之后,我们才会集成大型或向后兼容的更改。

实现 Promise

Promise 是具有 then 行为符合本规范的方法的对象或函数。

javascript
const promise = new Promise((resolve, reject) => {
	// 异步处理操作
	// 处理结束后调用resolve或reject
});

Promise States

Promise是一个状态机,有三种状态分别是pending(等待)fulfilled(完成态)rejected(失败态)。当Promise处于完成或者失败状态时,它的状态不可变

javascript
const PENDINT = 'pending';
const FULFILLED = 'fulfilled'; // 处于此状态时,状态不可变
const REJECTED = 'rejected'; // 处于此状态时,状态不可变
  • then 方法

Promise必须提供一种then访问其当前或最终价值或原因的方法。then方法接受两个参数,并且这两个必须是方法,且都有默认值

javascript
promise.then(onFulfilled, onRejected);
  • then 必须返回一个 Promise
javascript
then(onFulfilled, onRejected) {
      let promise2 = new Promise((resolve, reject) => {
          // 这里对返回值进行处理
      })
      return promise2;
  }

WARNING

  • 如果onFulFilled或者onRejected返回一个值x,需要对返回值进行处理
  • 如果任何一个onFulFilledonRejected发生异常e,则promise2必须以e为异常为onRejected理由

Promise Resolution Procedure

javascript
// 使用此函数对promise2和x进行处理
// 在`resolvePromise`函数中进行处理时,需要添加一个变量进行`Promise state`控制
resolvePromise(promise2, x, resolve, reject);
  • 如果xpromise2是同一个Object,则抛出类型错误

    javascript
    if (promise2 === x) {
    	return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
    }
  • 如果x是不为null的对象或者函数,则需要做取值 then 操作

    javascript
    if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
    	try {
    		let then = x.then;
    		if (typeof then === 'function') {
    			then.call(
    				x,
    				y => {
    					resolvePromise(promise2, y, resolve, reject);
    				},
    				r => {
    					reject(r);
    				}
    			);
    		} else {
    			resolve(x);
    		}
    	} catch (err) {
    		reject(err);
    	}
    	// 此过程中需要使用try catch 包裹,如果有错误,则调用reject
    } else {
    	// 如果`x`只是一个普通的值,则返回即可
    	resolve(x);
    }

My Promise 的全部实现代码

javascript
let PENDING = 'PENDING';
let RESOLVE = 'RESOLVE';
let REJECT = 'REJECT';

const isPromise = x => {
	if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
		if (typeof x.then === 'function') {
			return true;
		} else {
			return false;
		}
	} else {
		return false;
	}
};

const resolvePromise = (promise2, x, resolve, reject) => {
	// 判断promise2 和 x 是否相等,如果相等则会死循环
	if (promise2 === x) {
		return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
	}
	// 如果 x 是不为Null对象或者函数
	if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
		let called; // promise2的调用限制,防止多次调用成功和失败
		// 去取值的then,可能会出错,使用try
		try {
			let then = x.then;
			if (typeof then === 'function') {
				// 如果是函数,则去调用,调用要 call then user x
				// y => resolve , r => reject
				then.call(
					x,
					y => {
						if (called) {
							return;
						}
						called = true;
						// resolve中很可能再次返回一个Promise实例
						resolvePromise(promise2, y, resolve, reject);
						// resolve(y)
					},
					r => {
						if (called) {
							return;
						}
						called = true;
						reject(r);
					}
				);
			} else {
				if (called) {
					return;
				}
				called = true;
				resolve(x);
			}
		} catch (error) {
			if (called) {
				return;
			}
			called = true;
			reject(error);
		}
	} else {
		// 否则就是普通值
		resolve(x);
	}
};

class Promise {
	constructor(execute = () => {}) {
		// Promise整体状态
		this.status = PENDING;
		// 成功回调
		this.onFulfilledCb = [];
		// 失败回调
		this.onREjectedCb = [];

		let resolve = value => {
			if (this.status === PENDING) {
				this.status = RESOLVE;
				this.value = value;
				this.onFulfilledCb.forEach(cb => cb());
			}
		};

		let reject = value => {
			if (this.status === PENDING) {
				this.status = REJECT;
				this.value = value;
				this.onREjectedCb.forEach(cb => cb());
			}
		};

		// 如果执行函数内有错误,则直接抛出
		try {
			execute(resolve, reject);
		} catch (error) {
			reject(error);
		}
	}
	then(onFulfilled, onRejected) {
		// 判断是不是函数,如果是函数,则往下执行,如果不是函数,则给一个函数,返回当前值
		onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : data => data;
		onRejected =
			typeof onRejected === 'function'
				? onRejected
				: err => {
						throw err;
				  };

		let promise2 = new Promise((resolve, reject) => {
			// 同步执行
			// 成功执行
			if (this.status === RESOLVE) {
				/**
				 * 这段逻辑不可抽离出去,抽离出去会报错 cannot access 'promise2' before initialization
				 * 猜测可能在执行函数,将抽离出去的代码返回时,new Promise还没有执行完毕
				 */
				setTimeout(() => {
					try {
						let x = onFulfilled(this.value);
						resolvePromise(promise2, x, resolve, reject);
					} catch (error) {
						reject(error);
					}
				}, 0);
			}
			// 失败执行
			if (this.status === REJECT) {
				setTimeout(() => {
					try {
						let x = onRejected(this.value);
						resolvePromise(promise2, x, resolve, reject);
					} catch (error) {
						reject(error);
					}
				}, 0);
			}

			// 异步执行
			if (this.status === PENDING) {
				this.onFulfilledCb.push(() => {
					setTimeout(() => {
						try {
							let x = onFulfilled(this.value);
							resolvePromise(promise2, x, resolve, reject);
						} catch (error) {
							reject(error);
						}
					}, 0);
				});
				this.onREjectedCb.push(() => {
					setTimeout(() => {
						try {
							let x = onRejected(this.value);
							resolvePromise(promise2, x, resolve, reject);
						} catch (error) {
							reject(error);
						}
					}, 0);
				});
			}
		});

		return promise2;
	}
	finally(cb) {
		return this.then(
			// 这里将 resolve.then返回,是为了保证 cb 中的代码执行完毕,返回then中返回的Promise
			data => this.resolve(cb(data)).then(() => data),
			err =>
				this.resolve(cb(err)).then(() => {
					throw err;
				})
		);
	}
	static resolve = arg => {
		if (isPromise(arg)) {
			let promise2 = new Promise((resolve, reject) => {
				setTimeout(() => {
					try {
						let x = arg.then();
						resolvePromise(promise2, x, resolve, reject);
					} catch (error) {
						reject(error);
					}
				}, 0);
			});
			return promise2;
		} else {
			return new Promise(resolve => {
				resolve(arg);
			});
		}
	};
	static all = values => {
		return new Promise((resolve, reject) => {
			let arr = [];
			let index = 0;

			const pushIn = (key, data) => {
				arr[key] = data;
				index++;
				if (index === values.length) resolve(arr);
			};

			for (let i = 0; i < values.length; i++) {
				const item = values[i];
				if (isPromise(item)) {
					item.then(data => {
						pushIn(i, data);
					}, reject);
				} else {
					pushIn(i, item);
				}
			}
		});
	};

	static defer = () => {
		let dfd = {};
		dfd.promise = new Promise((resolve, reject) => {
			dfd.resolve = resolve;
			dfd.reject = reject;
		});
		return dfd;
	};
	static deferred = this.defer;

	static author = 'lxh';
}