promise 应该有三种状态. 要注意他们之间的流转关系.
1.1 初始的状态, 可改变.
1.2 一个 promise 在 resolve 或者 reject 前都处于这个状态。
1.3 可以通过 resolve -> fulfilled 状态;
1.4 可以通过 reject -> rejected 状态;
2.1 最终态, 不可变.
2.2 一个 promise 被 resolve 后会变成这个状态.
2.3 必须拥有一个 value 值
3.1 最终态, 不可变.
3.2 一个 promise 被 reject 后会变成这个状态
3.3 必须拥有一个 reason
Tips: 总结一下, 就是 promise 的状态流转是这样的
pending -> resolve(value) -> fulfilled
pending -> reject(reason) -> rejected
promise 应该提供一个 then 方法, 用来访问最终的结果, 无论是 value 还是 reason.
promise.then(onFulfilled, onRejected);
1.1 onFulfilled 必须是函数类型, 如果不是函数, 应该被忽略.
1.2 onRejected 必须是函数类型, 如果不是函数, 应该被忽略.
2.1 在 promise 变成 fulfilled 时,应该调用 onFulfilled, 参数是 value
2.2 在 promise 变成 fulfilled 之前, 不应该被调用.
2.3 只能被调用一次 (所以在实现的时候需要一个变量来限制执行次数)
3.1 在 promise 变成 rejected 时,应该调用 onRejected, 参数是 reason
3.2 在 promise 变成 rejected 之前, 不应该被调用.
3.3 只能被调用一次(所以在实现的时候需要一个变量来限制执行次数)
这里用queueMicrotask来实现微任务的调用.
5.1 promise 状态变成 fulfilled 后,所有的 onFulfilled 回调都需要按照then 的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个 onFulfilled 的回调)
5.2 promise 状态变成 rejected 后,所有的 onRejected 回调都需要按照then 的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个 onRejected 的回调)
promise2 = promise1.then(onFulfilled, onRejected);
6.1 onFulfilled 或 onRejected 执行的结果为 x, 调用 resolvePromise
6.2 如果 onFulfilled 或者 onRejected 执行时抛出异常 e, promise2 需要被 reject
6.3 如果 onFulfilled 不是一个函数, promise2 以 promise1 的 value 触发 fulfilled
6.4 如果 onRejected 不是一个函数, promise2 以 promise1 的 reason 触发 rejected
resolvePromise(promise2, x, resolve, reject);
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';class MyPromise {constructor(exec) {this.status = PENDING;this.value = null;this.reason = null;// 执行器传入后立即执行exec();}
}
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';class MyPromise {constructor(exec) {this.status = PENDING;this.value = null;this.reason = null;// resolve和reject被回调的时候,状态流转// 这里使用箭头函数,绑定resolve和reject的this始终指向MyPromiselet resolve = (value) => {if (this.status === PENDING) {this.status = FULFILLED;this.value = value;}};let reject = (reason) => {if (this.status === PENDING) {this.status = REJECTED;this.reason = reason;}};// 若执行器报错,直接reject出去try {// 执行器传入后立即执行exec(resolve, reject);} catch (error) {reject(error);}}
}
then(onFulfilled, onRejected) {if (this.status === FULFILLED) {// 调用成功回调,并且把值返回onFulfilled(this.value);} else if (this.status === REJECTED) {// 调用失败回调,并且把原因返回onRejected(this.reason);}
}
到这个地方一个简单的 promise 的骨架已经形成了,写一个测试检查一下
const promise = new MyPromise((resolve, reject) => {resolve('success');reject('err');// 如果这里使用异步的方法,上述的then是感觉不到的// setTimeout(() => {// resolve('success')// })
});promise.then((value) => {console.log('resolve', value);},(reason) => {console.log('reject', reason);},
);// 输出: resolve success
思考:为什么使用异步的方法就感受不到了呢?
上面的写法, 是在 then 函数被调用的瞬间就会执行.
那这时候如果 status 还没变成 fulfilled 或者 rejected 怎么办, 很有可能还是 pending 的
那么我们首先要拿到所有的回调, 然后才能在某个时机去执行他.
新建两个数组, 来分别存储成功和失败的回调, 调用 then 的时候, 如果还是 pending 就存入数组
class MyPromise {constructor(exec) {this.status = PENDING;this.value = null;this.reason = null;this.resolveCallbacks = [];this.rejectCallbacks = [];// resolve和reject被回调的时候,状态流转// 这里使用箭头函数,绑定resolve和reject的this始终指向MyPromiselet resolve = (value) => {if (this.status === PENDING) {this.status = FULFILLED;this.value = value;this.resolveCallbacks.forEach((fn) => fn());}};let reject = (reason) => {if (this.status === PENDING) {this.status = REJECTED;this.reason = reason;this.rejectCallbacks.forEach((fn) => fn());}};// 若执行器报错,直接reject出去try {// 执行器传入后立即执行exec(resolve, reject);} catch (error) {reject(error);}}then(onFulfilled, onRejected) {if (this.status === FULFILLED) {// 调用成功回调,并且把值返回onFulfilled(this.value);} else if (this.status === REJECTED) {// 调用失败回调,并且把原因返回onRejected(this.reason);} else if (this.status === PENDING) {this.resolveCallbacks.push(onFulfilled);this.rejectCallbacks.push(onRejected);}}
}
isFunction(params) {return typeof params === 'function';
}then(onFulfilled, onRejected) {// 1.onFulfilled和onRejected如果不是函数,就返回原value或reasonconst fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : value => value;const rejectedFn = this.isFunction(onRejected) ? onRejected : reason => { throw reason };// 2.then方法返回一个promise对象const p2 = new MyPromise((resolve, reject) => {if (this.status === FULFILLED) {// fulFilledFn(this.value)// 3.3. onFulfilled和onRejected是微任务,需要使用queueMicrotask或者setTimeout包裹queueMicrotask(() => {// 2.2 如果onFulfilled或者onRejected执行时抛出异常e,promise2需要被reject,其reason为etry {// 2.1 onFulfilled或onRejected执行的结果是x,调用resolvePromise// 获取成功回调函数的执行结果const x = fulFilledFn(this.value);// 传入 resolvePromise 集中处理this.resolvePromise(p2, x, resolve, reject);} catch (e) {reject(e);}})} else if (this.status === REJECTED) {// rejectedFn(this.reason);queueMicrotask(() => {try {const x = rejectedFn(this.value);// 传入 resolvePromise 集中处理this.resolvePromise(x, resolve, reject);} catch (e) {reject(e);}})} else if (this.status === PENDING) {this.resolveCallbacks.push(() => {queueMicrotask(() => {try {const x = fulFilledFn(this.value);// 传入 resolvePromise 集中处理this.resolvePromise(x, resolve, reject);} catch (e) {reject(e);}})});this.rejectCallbacks.push(() => {queueMicrotask(() => {try {const x = rejectedFn(this.value);// 传入 resolvePromise 集中处理this.resolvePromise(x, resolve, reject);} catch (e) {reject(e);}})});}});return p2;
}resolvePromise(x, resolve, reject) {// 判断x是不是 MyPromise 实例对象if (x instanceof MyPromise) {// 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected// x.then(value => resolve(value), reason => reject(reason))// 简化之后x.then(resolve, reject);} else {// 普通值resolve(x);}
}
发现上面 promise2 中很多重复的代码,进行抽离
then(onFulfilled, onRejected) {// 1.onFulfilled和onRejected如果不是函数,就返回原value或reasonconst fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : value => value;const rejectedFn = this.isFunction(onRejected) ? onRejected : reason => { throw reason };// 2.then方法返回一个promise对象const p2 = new MyPromise((resolve, reject) => {const fulfilledMicrotask = () => {// 3.3. onFulfilled和onRejected是微任务,需要使用queueMicrotask或者setTimeout包裹queueMicrotask(() => {// 2.2 如果onFulfilled或者onRejected执行时抛出异常e,promise2需要被reject,其reason为etry {// 2.1 onFulfilled或onRejected执行的结果是x,调用resolvePromise// 获取成功回调函数的执行结果const x = fulFilledFn(this.value);// 传入 resolvePromise 集中处理this.resolvePromise(p2, x, resolve, reject);} catch (e) {reject(e);}})}const rejectedMicrotask = () => {queueMicrotask(() => {try {const x = rejectedFn(this.reason);// 传入 resolvePromise 集中处理this.resolvePromise(p2, x, resolve, reject);} catch (e) {reject(e);}})}if (this.status === FULFILLED) {// fulFilledFn(this.value)fulfilledMicrotask();} else if (this.status === REJECTED) {// rejectedFn(this.reason);rejectedMicrotask();} else if (this.status === PENDING) {this.resolveCallbacks.push(fulfilledMicrotask);this.rejectCallbacks.push(rejectedMicrotask);}});return p2;
}
其实整体的处理逻辑与原来相似,不过是对边界情况更加细化了
resolvePromise(x, resolve, reject) {// 判断x是不是 MyPromise 实例对象if (x instanceof MyPromise) {// 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected// x.then(value => resolve(value), reason => reject(reason))// 简化之后x.then(resolve, reject);} else {// 普通值resolve(x);}
}
resolvePromise(promise2, x, resolve, reject);
resolvePromise(promise2, x, resolve, reject) {if (promise2 === x) {throw new TypeError('循环引用')}if (typeof x === 'object' || typeof x === 'function') {if (x === null) {return resolve(x);}let then;try {then = x.then;} catch (e) {return reject(e);}if (typeof then === 'function') {let called = false;try {then.call(x, y => {if (called) return;called = true;this.resolvePromise(promise2, y, resolve, reject)}, r => {if (called) return;called = true;reject(r);})} catch (e) {if (called) return;reject(e);}} else {resolve(x);}} else {resolve(x);}
}
static resolve(params) {if (params instanceof MyPromise) {return params;}return new MyPromise((resolve, reject) => {resolve(params);})}static reject(reason) {return new MyPromise((resolve, reject) => {reject(reason);})
}catch(onRejected){return this.then(null, onRejected)
}
const p = Promise.race([p1, p2, p3]);
该方法是将多个 Promise 实例,包装成一个新的 Promise 实例。
只要 p1、p2、p3 之中有一个实例率先改变状态,p 的状态就跟着改变。
那个率先改变的 Promise 实例的返回值,就传递给 p 的回调函数。
static race(promises) {if (!Array.isArray(promises)) {throw new TypeError('arguments must be an array')}return new MyPromise((resolve, reject) => {if (promises.length === 0) {return resolve();}for (let i = 0; i < promises.length; i++) {MyPromise.resolve(promises[i]).then(resolve, reject);}})
}static all(promises) {return new MyPromise((resolve, reject) => {if (!Array.isArray(promises)) {throw new TypeError('arguments must be an array')}if (promises.length === 0) {return resolve([]);}let result = [];let count = 0;for (let i = 0; i < promises.length; i++) {MyPromise.resolve(promises[i]).then(value => {result[i] = value;count++;if (count === promises.length) {resolve(result);}}, reject);}})
}// 返回所有promise的状态和结果
static allSettled(promises) {return new MyPromise((resolve, reject) => {if (!Array.isArray(promises)) {throw new TypeError('arguments must be an array')}let count = 0;let result = [];for (let i = 0; i < promises.length; i++) {MyPromise.resolve(promises[i]).then(value => {result[i] = {status: 'fulfilled',value}count++;if (count === promises.length) {resolve(result);}}, reason => {result[i] = {status: 'rejected',reason}count++;if (count === promises.length) {resolve(result);}})}})
}
// npm i promises-aplus-tests -g
// 命令行执行 => promises-aplus-tests [待测试文件] 即可验证
MyPromise.deferred = function () {var result = {};result.promise = new MyPromise(function (resolve, reject) {result.resolve = resolve;result.reject = reject;});return result;
};
module.exports = MyPromise;
上一篇:C51---定时器中断相关寄存器
下一篇:《华为数据之道》读书笔记