上篇回顾
promise专题–手写promise02
上篇我们解决了异步调用的问题,但是发现链式调用是行不通的。这篇解决这个问题。
一、问题分析
原生promise为什么支持then的链式调用?因为原生每次then之后会返回一个promise对象,所以可以支持链式调用,但是上篇我们写的并没有返回一个promise对象,所以当我们再then的时候,就是undefined.then,所以理所当然直接报错喽,所以链式调用的核心就是要返回一个promise对象,下面看怎么做!
二、重写then方法
1、因为要返回一个promise对象,所以我们直接搭建新的代码框架,具体为
Promise.prototype.then = function (onFulfilled, onRejected) {
let newPromise = new Promise((resolve, reject) => {})
return newPromise ;
}
2、重写上一篇的三种情况,因为每次返回一个promise,所以我们得知道上一个执行的到底是成功了还是失败了,所以当拿到结果的时候我们需要一个方法来解析这个promise到底是成功了还是失败了。
Promise.prototype.then = function (onFulfilled, onRejected) {
let newPromise = new Promise((resolve, reject) => {
if (_this.status === "fulfilled") {
setTimeout(() => {
// 需要使用newPromise,所以需要放入异步代码中
try {
let res = onFulfilled(_this.successValue);
//resolve(res);
// 对res进行解析判断
resolvePromise(promise2, res, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
}
})
return newPromise ;
}
function resolvePromise(promise,res, resolve, reject) {
// 这里需要判断一个循环引用的问题
if (res === promise) {
return reject(new TypeError("循环引用!"));
}
// 判断是否是一个对象或者函数
if (res != null && typeof res === 'object' || typeof res === 'function') {
// 判断是否是promise
try {
let then = res.then; // then有可能抛出异常
if (typeof then === 'function') {
// 将其认为是一个promise,然后执行then
then.call(res, (y) => {
resolve(y);
}, (r) => {
reject(r);
});
} else {
// 认为是一个普通的值
resolve(res);
}
}catch (e) {
reject(e);
}
} else {
// 非引用类型 也就是一个普通值
resolve(res);
}
}
3、失败和异步的重写如下,整体代码如下:
Promise.prototype.then = function (onFulfilled, onRejected) {
let _this = this;
// then被执行,需要再次返回一个新的promise实例
// 需要拿到当前then方法的结果也就是得知道成功或者失败
let newPromise = new Promise((resolve, reject) => {
if (_this.status === "fulfilled") {
setTimeout(() => {
// 需要使用promise2,所以需要放入异步代码中
try {
let res = onFulfilled(_this.successValue);
//resolve(res);
// 对res进行解析判断
resolvePromise(newPromise, res, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
}
if (_this.status === "rejected") {
setTimeout(() => {
try {
let res = onRejected(_this.errReason);
resolvePromise(newPromise, res, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
}
if (_this.status === "pending") {
_this.onResolvedCallbacks.push(function () {
setTimeout(() => {
try {
let res = onFulfilled(_this.successValue);
resolvePromise(newPromise, res, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
})
_this.onRejectedCallbacks.push(function () {
setTimeout(() => {
try {
let res = onRejected(_this.errReason);
resolvePromise(newPromise, res, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
})
}
});
return newPromise;
}
三、大体思路
1.能够链式调用,肯定then方法最后需要返回一个Promise实例;
2. 在then方法中用res去接收成功或者失败的返回值,当成功或失败方法抛出错误,直接执行reject。因为要分析成功或者失败的回调,所以专门抽出一个方法resolvePromise用来分析返回值;
3. resolvePromise方法中传入了四个参数,then中的newPromise,res值;
4. 如果res与promise相等,说明重复引用了,直接报错干掉;
5. 当res不是null,是个对象类型or函数类型,并且他的then方法也是函数类型时,就可以认为res他是个promise实例,执行x.then()方法;再用resolvePromise方法分析他的成功的返回值即可;
6. 如果res不是null不是object或function,就可以将其认为一个普通值,执行resolve方法即可;
7. 如果res.then方法抛出异常了,直接调用reject方法就ok喽;
四、支持then穿透
原生promise支持then穿透也就是
p.then().then().then(()= > {....})
如何实现?
思路: then方法返回执行promise前,判断下,如果是穿透的话,返回的不是一个function类型,处理下就ok
Promise.prototype.then = function (onFulfilled, onRejected) {
// 穿透处理
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : data => data;
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason
}
.......
}
下一篇实现all, race, resolve,reject,catch,finally方法