一、前言
作为面试中高频出现的面试题----手写一个符合Promise+规范的Promise.一开始是蒙的,完全没有思路,但是看过很多人的各种文章解析之后有了自己的思路。
其实手写几遍符合规范的promise之后,很多之前对于promise执行的疑惑就都一一解开了,有一种豁然开朗的感觉,其实我说的是在做event loop的题的时候,遇到promise人就傻了,但是更深入了解promise之后就很多问题迎刃而解。
二、关于一个Promise要有哪些注意的点,根据别人的文章,总结一下(参考别人思路并拓展加入一些自己的见解)
-
- new Promise时,需要传递一个 executor 执行器,执行器立刻执行
-
- executor 接受两个参数,分别是 resolve 和 reject
-
- promise 只能从 pending 到 rejected, 或者从 pending 到 fulfilled
-
- promise 的状态一旦确认,就不会再改变
-
- promise 都有 then 方法,then 接收两个参数,分别是 promise 成功的回调 onFulfilled, 和 promise 失败的回调 onRejected
-
- 如果调用 then 时,promise已经成功,则执行 onFulfilled,并将promise的值作为参数传递进去。如果promise已经失败,那么执行 onRejected, 并将 promise 失败的原因作为参数传递进去。如果promise的状态是pending,需要将onFulfilled和onRejected函数存放起来,等待状态确定后,再依次将对应的函数执行(发布订阅)
-
- then 的参数 onFulfilled 和 onRejected 可以缺省
-
- promise 可以then多次,promise 的then 方法返回一个 promise
-
- 如果 then 返回的是一个结果,那么就会把这个结果作为参数,传递给下一个then的成功的回调(onFulfilled)
-
- 如果 then 中抛出了异常,那么就会把这个异常作为参数,传递给下一个then的失败的回调(onRejected)
-
- 如果 then 返回的是一个promise,那么需要等这个promise,那么会等这个promise执行完,promise如果成功,就走下一个then的成功,如果失败,就走下一个then的失败
三、手撸promise
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function myPromise(excutor) {
let self = this;
// 一个promise要有这五个值
self.status = PENDING;
self.value = null;
self.reason = null;
// 当状态一直是PENDING 的时候需要存起来
self.onFulfilledCallBacks = [];
self.onRejectedCallBacks = [];
// excutor 中 resolve 函数, value 为要传的值
function resolve(value) {
// 避免多次resolve
if (self.status === PENDING) {
self.value = value;
self.status = FULFILLED;
self.onFulfilledCallBacks.forEach(fn => fn());
}
}
// excutor 中 reject 函数, reson 为要传的值
function reject(reson) {
// 避免多次 reject
if (self.status === PENDING) {
self.reason = reson;
self.status = REJECTED;
self.onRejectedCallBacks.forEach(fn => fn());
}
}
// excutor立即执行
try {
excutor(resolve, reject);
} catch(e) {
reject(e);
}
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
// 由于onFulfilled, onRejected可以缺省 所以一开始要判定下是否为可执行的函数
// onFulfilled如果缺省的话默认执行一个返回传参的函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected如果缺省的话默认执行一个抛出reason的函数
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
// 由于then函数本身是一个promise(能链式调用),所以新声明一个promise
let self = this;
let promise2 = new myPromise((resolve, reject) => {
// 执行成功态
if (self.status === FULFILLED) {
// onFulfilled要放到异步里执行,这里是模拟用settimeout,实际上promise是在V8引擎里实现了异步
setTimeout(() => {
try {
// x 为 onFulfilled的返回值
let x = onFulfilled(self.value);
// 递归调用 下个then(链式调用)
resolvePromise(promise2, x, resolve, reject);
} catch(e) {
reject(e)
}
}, 0);
}
// 执行失败态
if (self.status === REJECTED) {
setTimeout(() => {
try {
// x 为 Reject 的返回值
let x = onRejected(self.reason);
// 递归调用 下个then(链式调用)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0);
}
// 执行等待态
if (self.status === PENDING) {
// 如果是pending态 就先存起来
self.onFulfilledCallBacks.push(() => {
setTimeout(() => {
try {
// x 为 onFulfilled的返回值
let x = onFulfilled(self.value);
// 递归调用 下个then(链式调用)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0);
})
self.onRejectedCallBacks.push(() => {
setTimeout(() => {
try {
// x 为 Reject 的返回值
let x = onRejected(self.reason);
// 递归调用 下个then(链式调用)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0);
})
}
})
return promise2;
}
function resolvePromise(promise2, x, resolve, reject) {
let self = this;
// 首先先判断下是否是调动promise2 本身,是的话就是循环调用
if (promise2 === x) {
return reject(new TypeError('chaining cycle'));
}
let called;
if (typeof x === 'object' && x || typeof x === 'function') {
// 里面递归调用了resolvePromise,所以还是用try catch包起来
try {
let then = x.then;
if (typeof then === 'function') {
console.log('x为promise------')
then.call(x, y => {
// 只能有一次终态
if (called) return;
called = true;
// 继续递归
resolvePromise(promise2, y, resolve, reject);
}, r => {
// 只能有一次终态
if (called) return;
called = true;
reject(r);
})
} else {
console.log('x为有值 值为function或x.then不为function时------')
// 只能有一次终态
if (called) return;
called = true;
resolve(x);
}
} catch(e) {
// 只能有一次终态
if (called) return;
called = true;
reject(e);
}
} else {
console.log('x为undefined或者明确的值时 ------')
resolve(x);
}
}
后续补充例子。。理解代码的例子