实现一个复杂版本的promise
function PromiseA(executor){
this.status = 'pending'
// 成功value
this.value = undefined;
// 失败reason
this.reason = undefined;
// 成功监听数组
this.succArr = [];
// 失败监听数组
this.errArr = [];
var that = this;
function resolve(value){
if(that.status === 'pending'){
that.status = 'resolved';
that.value = value;
that.succArr.forEach(function (item) {
item(that.value)
})
}
}
function reject(reason) {
if(that.status === 'pending'){
that.status = 'rejected';
that.reason = reason;
that.errArr.forEach(function (item) {
item(that.reason)
})
}
}
try {
executor(resolve,reject)
}catch (e) {
reject(e)
}
}
PromiseA.prototype = {
constructor:PromiseA,
then:function (succFn,errFn) {
var that = this;
var Promise2;
// catch函数的核心
errFn = typeof errFn === 'function' ? errFn : function(err){ throw err}
Promise2 = new PromiseA(function(resolve,reject){
if(that.status === 'pending'){
that.succArr.push(function () {
// 解决异步问题,其实promise属于微任务,这里用宏任务模拟异步
setTimeout(function () {
try{
// then函数的返回值会包装成新的promise
var x = succFn(that.value);
that.resolvePromise(Promise2, x, resolve, reject);
}catch (e) {
reject(e);
}
},0)
});
that.errArr.push(function () {
setTimeout(function () {
try{
var x = errFn(that.reason);
that.resolvePromise(Promise2, x, resolve, reject);
}catch (e) {
reject(e);
}
},0)
})
}
/*
* 为什么还要对status === 'resolved' 和 'rejected'做相关处理呢?
* 原因:如果promise内部是异步函数,不做相关处理也是可以的,但是对于内部是同步代码时,当执行resolve时,sussArr还未push到then内部函数,导致无法执行then内部函数
*
* */
if(that.status === 'resolved'){
setTimeout(function () {
try{
// then函数的返回值会包装成新的promise
var x = succFn(that.value);
that.resolvePromise(Promise2, x, resolve, reject);
}catch (e) {
reject(e);
}
},0)
}
if(that.status === 'rejected'){
setTimeout(function () {
try{
var x = errFn(that.reason);
that.resolvePromise(Promise2, x, resolve, reject);
}catch (e) {
reject(e);
}
},0)
}
});
return Promise2;
},
/*
* @desc:resolvePromise主要解决 then内部 return { then:function(){}} return function(){} ruturn new Promise情况
* @这是Promise规范中的方法,了解流程即可
* 其终极目的: resolve(data)
*
* 这个函数比较难理解
* */
resolvePromise: function(promise2, x, resolve, reject) {
let self = this;
let called = false; // called 防止多次调用
if (promise2 === x) {
return reject(new TypeError('循环引用'));
}
if (x !== null && (Object.prototype.toString.call(x) === '[object Object]' || Object.prototype.toString.call(x) === '[object Function]')) {
// x是对象或者函数
try {
let then = x.then;
if (typeof then === 'function') {
/*
* 难点:当返回是个promise时,但是确保其resolve reject要传递到我们写的下一个then
*
* 1.当第一次调用then时,其实已经生成了一个新的promiseX
* 2.then内部函数又返回一个promiseY,但是在调用下一个then时,我们使用的时promiseX,那如何保证promiseY的resolve值传递到promiseX呢?
* 3.除非我们可以用promiseX的resolve(promiseY的resolve的值)
* 4.解决方法,内部调用then方法,将promiseY的resolve的值传递下来
* 5.递归处理
* 6.牢记我们这个函数的目的: promiseX的resolve(data)
* */
then.call(x, (y) => {
// 别人的Promise的then方法可能设置了getter等,使用called防止多次调用then方法
if (called) return ;
called = true;
// 成功值y有可能还是promise或者是具有then方法等,再次resolvePromise,直到成功值为基本类型或者非thenable
self.resolvePromise(promise2, y, resolve, reject);
}, (reason) => {
if (called) return ;
called = true;
reject(reason);
});
} else {
if (called) return ;
called = true;
resolve(x);
}
} catch (reason) {
if (called) return ;
called = true;
reject(reason);
}
} else {
// x是普通值,直接resolve
resolve(x);
}
},
//实现catch函数:promise链中所有错误都会捕获
catch:function (errFn) {
// 其实只要给then内部的errFn添加一个默认函数即可,因为每次then都会向下传递,所有catch写到后面即可捕获到错误
return this.then(null,errFn)
}
}