// 考虑到兼容性问题,不使用ES6+
; (function () {
// 构造函数constructor
function MyPromise(executor) {
// 参数合法校验
if (typeof executor !== "function") {
throw new TypeError('MyPromise resolver ' + executor + ' is not a function');
}
// 设置实例的私有属性
var _this = this;
this.PromiseStatus = 'pending';
this.PromiseValue = undefined;
// 【1、实例的resolveFunc函数、rejectFunc函数,为了拿到then中的2个函数,把这2个函数挂载到实例上; 2、值设置为空函数的好处,就是支持resolve方法中不写then。】
this.resolveFunc = function () { };
this.rejectFunc = function () { };
// 修改实例的状态和value:只有当前状态为pending才能修改状态
function change(status, value) {
// 下面的_this.PromiseStatus不能用传递进来的status
if (_this.PromiseStatus !== "pending") return;
_this.PromiseStatus = status;
_this.PromiseValue = value;
// 通知基于.then注入的某个方法执行(执行resolve、reject都是异步的)
// 【用等待时间为0的setTimeout模拟微任务】
var delayTimer = setTimeout(function () {
clearTimeout(delayTimer);
delayTimer = null;
// 不用重新定义变量,直接用上面的_this.PromiseStatus、_this.PromiseValue即可
var status = _this.PromiseStatus;
var value = _this.PromiseValue;
// 把.then注入的某个方法执行拿出来执行
status === "fulfilled" ?
_this.resolveFunc.call(_this, value) :
_this.rejectFunc.call(_this, value);
}, 0);
}
// new MyPromise的时候会给 resolve函数传参value
function resolve(value) {
change('fulfilled', value);
}
// new MyPromise的时候会给 reject函数传参reason
function reject(reason) {
change('rejected', reason);
}
// new MyPromise的时候会立即把executor函数执行,executor函数中的第一、二个参数分别为resolve、reject函数
// executor函数执行出现错误,也会把实例的状态改为失败,且value是失败的原因
try {
// 【执行executor,就会根据情况执行resolve、reject中的一个,然后去执行change,再然后决定执行resolveFunc、rejectFunc中的一个】
executor(resolve, reject);
} catch (err) {
change('rejected', err.message);
}
}
// 把MyPromise当作对象
MyPromise.resolve = function (value) {
// 创建一个状态为成功的实例,通知这个实例的then中的某个方法执行。如果没有写then,定时器到达一定时间之后,就会去执行成功或失败的方法,但是实例没有成功和失败的方法。
return new MyPromise(function (resolve) {
resolve(value);
});
};
MyPromise.reject = function (reason) {
// function的形参可以下划线占位,不能用null
return new MyPromise(function (_, reject) {
reject(reason);
});
};
// MyPromise.prototype
// 不仅要把resolveFunc、rejectFunc挂载到 实例上,还要知道resolveFunc、rejectFunc执行的时候,是否报错,以及返回值是什么;最后还要返回一个新的promise实例
MyPromise.prototype.then = function (resolveFunc, rejectFunc) {
// 参数不传默认值的处理:目的是实现状态的顺延 【不传,或者传的不是函数】
if (typeof resolveFunc !== "function") {
// (1) 形参value从哪来?promise实例中执行resolve()传递的数据;加一个函数,这个函数可以接收到value; (2) 不是this.resolveFunc
resolveFunc = function (value) {
// 【不传,或者传的不是函数时】怎么往下顺延呢?返回一个resolve即可
return MyPromise.resolve(value);
};
}
if (typeof rejectFunc !== "function") {
rejectFunc = function (reason) {
return MyPromise.reject(reason);
};
}
var _this = this;
// resolveFunc、rejectFunc执行的成功、失败直接影响了新返回的MyPromise的成功、失败
// 返回的新实例的成功和失败由resolveFunc、rejectFunc执行是否报错来决定,或者由返回值是否为新的MyPromise实例来决定
return new MyPromise(function (resolve, reject) {
// 最终目的是执行resolveFunc,外面包一层匿名函数,是想知道resolveFunc执行时,是否报错,返回值是什么
// document.body.onclick = fn,如果想 改变fn的值、this、预先传参等等,就先绑定一个匿名函数,document.body.onclick = function() { fn() }
// value 要写在外层的匿名函数中
_this.resolveFunc = function (value) {
// 这里面的this就是实例了,因为执行change方法,传过来的就是实例,也可以用this写
try {
// 1、用不用call改变this都可以;2、then的2个回调函数参数有返回值; 3、value是resolveFunc接收【实例】的返回结果
var x = resolveFunc.call(_this, value);
// 1、不是promise实例,一定是成功的,执行resolve;2、如果x是promise实例,then会通知resolve或reject执行,通知resolve执行,返回的new MyPromise就是成功的,通知reject执行,返回的new MyPromise就是失败的。如果返回的新实例x是失败的,就执行reject,new MyPromise就是失败的,反之是成功的。
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
} catch (err) {
reject(err.message);
}
};
_this.rejectFunc = function (reason) {
try {
var x = rejectFunc.call(_this, reason);
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
} catch (err) {
reject(err.message);
}
};
});
};
MyPromise.prototype.catch = function (rejectFunc) {
return this.then(null, rejectFunc);
};
MyPromise.all = function (promiseArr) {
return new MyPromise(function (resolve, reject) {
var index = 0; // 成功的个数
var values = [];
for (var i = 0; i < promiseArr.length; i++) {
// 利用闭包的方式保存循环的每一项索引
(function (i) {
var item = promiseArr[i];
// 如果当前项不是Promise,直接算作当前项成功
!(item instanceof MyPromise) ? item = MyPromise.resolve(item) : null;
// 回调函数的参数 value、reason来自于 race中的参数 promise实例的promiseValue
item.then(function (value) {
index++;
// 不是values[i] = item,item是promise实例,value才是实例的值
values[i] = value;
if (index >= promiseArr.length) {
resolve(values); // 所有的实例都是成功的
}
}).catch(function (reason) {
reject(reason); // 只要有一个失败,整体就是失败的
});
})(i);
}
});
};
// 补充race
MyPromise.race = function (promises) {
return new MyPromise(function (resolve, reject) {
promises.forEach(function (p) {
!(p instanceof MyPromise) ? p = MyPromise.resolve(p) : null
// 回调函数的参数 value、reason来自于 race中的参数 promise实例的promiseValue
p.then(function (value) {
resolve(value)
}).catch(function (reason) {
reject(reason)
})
})
})
}
// 补充finally
Promise.prototype.finally = function (callback) {
let P = this.constructor;
// 不管成功、失败,都会执行callback,放到this.then中,成功执行P.resolve,并在P.resolve中执行callback;失败同理。
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
window.MyPromise = MyPromise;
})();
// ------------------------------------
function fn1() {
return MyPromise.resolve(1);
}
function fn2() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(2);
}, 2000);
});
}
function fn3() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
reject(3);
}, 1000);
});
}
MyPromise.all([fn1(), fn2(), fn3(), 10])
.then(function (values) {
console.log('OK', values);
})
.catch(function (reason) {
console.log('NO', reason);
});
new MyPromise(function (resolve, reject) {
// resolve(10);
reject(20);
}).then(function (value) {
console.log('OK', value);
return MyPromise.reject(200);
},
/* function (reason) {
console.log('NO', reason);
return 100;
} */
).then(function (value) {
console.log('OK', value);
}, function (reason) {
console.log('NO', reason);
});