前言
我们引入了Promise,它允许我们简化异步流程,避免回调的麻烦。手写Promise,那我是不是也要写一个瞅瞅呢?
实现思路
- 构造函数,该构造函数会把一个叫做“处理器函数”(executor function)的函数作为它的参数。这个“处理器函数”接受两个函数——
resolve和reject——作为其参数。 - 当异步任务顺利完成且返回结果值时,会调用
resolve函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject函数。 - 构造函数结构,状态管理,state,暂存异步后的返回值,暂存异步成功后后需要处理的函数,暂存异步处理后失败需要处理的函数
代码实现(Promise)
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function MyPromise(executor) {
const _this = this;
this.state = PENDING;
this.value = undefined;
this.onFulfilled = [];
this.onRejected = [];
function resolve(value) {
if(_this.state === PENDING){
_this.state = FULFILLED;
_this.value = value;
// for(let i in _this.onFulfilled){
// _this.onFulfilled[i](value)
// }
}
}
function reject(value) {
if(_this.state === PENDING){
console.log('reject')
_this.state = REJECTED;
_this.value = value;
// for(let i in _this.onRejected){
// _this.onRejected[i](value)
// }
}
}
try {
console.log(111)
executor(resolve,reject);
} catch (error) {
console.log(22)
reject(error);
}
}
MyPromise.prototype.then = function(onFulfilled,onRejected) {
console.log('执行then方法')
console.log(this.state,'this.state')
if(this.state === FULFILLED){
typeof onFulfilled === 'function' && onFulfilled(this.value)
}
if(this.state === REJECTED){
typeof onRejected === 'function' && onRejected(this.reason)
}
// if(this.state === PENDING){
// typeof onFulfilled === 'function' && this.onFulfilled.push(onFulfilled)
// typeof onRejected === 'function' && this.onRejected.push(onRejected)
// }
}
new MyPromise((a,b) => {
console.log('异步请求开始')
setTimeout(() => {
a('异步请求结束')
},2000)
console.log('执行异步请求')
}).then((res) => {
console.log(res)
});
console.log(888)
此处输出的结果是:
会发现没有打印出异步请求结束的语句,经过分析发现:当then里面函数运行时,resolve由于是异步执行的,还没有来得及修改state,所以执行then时state的状态会是PENDING状态,不会执行onFulfilled和onRejected函数;所以需要处理将成功或失败的函数放到数组中暂存起来,当异步响应成功过或失败时去执行对应的函数,即打开上述代码中注释掉的部分即可。
Promise链式调用
上述的 MyPromise 构造函数是.then方法是没有返回值的,如果想支持链式调用必须有返回值,且返回值包含then方法,那么我们只需要在.then方法中返回一个新的MyPromise实例即可:
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function MyPromise(executor) {
const _this = this;
this.state = PENDING;
this.value = undefined;
this.onFulfilled = [];
this.onRejected = [];
function resolve(value) {
if(_this.state === PENDING){
_this.state = FULFILLED;
_this.value = value;
for(let i in _this.onFulfilled){
_this.onFulfilled[i](_this.value)
}
}
}
function reject(value) {
if(_this.state === PENDING){
console.log('reject')
_this.state = REJECTED;
_this.value = value;
for(let i in _this.onRejected){
_this.onRejected[i](_this.value)
}
}
}
try {
executor(resolve,reject);
} catch (error) {
reject(error);
}
}
MyPromise.prototype.then = function(onFulfilled,onRejected) {
let that = this;
return new MyPromise((resolve,reject) => {
if(that.state === FULFILLED && typeof onFulfilled === 'function'){
let res = onFulfilled(that.value)
resolve(res);
}
if(that.state === REJECTED && typeof onRejected === 'function'){
let error = onRejected(that.reason)
reject(error);
}
if(that.state === PENDING){
that.onFulfilled.push(() => {
const res = onFulfilled(that.value)
resolve(res)
})
that.onRejected.push(() => {
const reason = onRejected(that.reason)
reject(reason)
})
}
})
}
new MyPromise((a,b) => {
setTimeout(() => {
a('66666')
},2000)
}).then((res) => {
console.log(res,'mmmm')
return '异步请求结果2';
}).then(res => {
console.log(res,'ssss')
});
代码实现(Promise.all)
- 分析:
- 该方法挂在原型上
- 返回结果也是promise
- 传入输入数组,需要对传入参数做类型判断
- 遍历数组,数组元素,可能不是promise,需要做类型判断,如果判断可以手动转成promise
- 所有传入promsie全部处理完成返回结果,且传入需要和输入出结果一一对应,如何一一对应呢,可以用计数器
- 特性:传入的promise全部成功则成功,一个失败则整体失败
- 代码:
Promise.all = function(promiseArray){
return new Promise((resolve,reject) => {
if(!Array.isArray(promiseArray)) return new typeError('参数错误');
let len = promiseArray.length;
let resultArr = [];
let counter = 0;
for(let i = 0; i < len; i++ ){
Promise.resolve(promiseArray[i]).then(res => {
counter++;
resultArr[i] = res;
if(counter === len) resolve(resultArr);
}).catch(error => {
reject(error)
})
}
})
}
- 测试用例
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("1", 1);
resolve(1);
}, 1000);
});
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("2", 2);
resolve(2);
}, 2000);
});
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("3", 3);
resolve(3);
}, 3000);
});
输出结果: // 1 1 // 2 2 // 3 3 // res [ 1, 2, 3 ]
代码实现(Promise.race)
- 分析:
- 该方法挂在原型上
- 返回结果也是promise
- 传入输入数组,需要对传入参数做类型判断
- 遍历数组,数组元素,可能不是promise,需要做类型判断,如果判断可以手动转成promise
- 返回结果只需返回第一个处理完成的promise
- 特性:直接返回第一个响应的promise,无论成功失败
- 代码:
Promise.race = function (promiseArray) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promiseArray)) return new typeError("参数错误");
let len = promiseArray.length;
let resultArr = [];
let counter = 0;
for (let i = 0; i < len; i++) {
Promise.resolve(promiseArray[i])
.then(res => {
counter++;
if (counter === 1) {
resolve(res);
}
})
.catch(error => {
reject(error);
});
}
});
};
代码实现(Promise.allSettled)
- 分析:
- 该方法挂在原型上
- 返回结果也是promise
- 传入输入数组,需要对传入参数做类型判断
- 遍历数组,数组元素,可能不是promise,需要做类型判断,如果判断可以手动转成promise
- 返回结果无论成功失败,全部处理完之后统一返回结果
- 特性:无论成功失败,全部处理完之后统一返回
- 代码:
Promise.allSettled = function (promiseArray) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promiseArray)) return new typeError("参数错误");
let len = promiseArray.length;
let resultArr = [];
let counter = 0;
for (let i = 0; i < len; i++) {
Promise.resolve(promiseArray[i])
.then(res => {
counter++;
resultArr[i] = { staus: "status", value: res };
if (counter === len) {
resolve(resultArr);
}
})
.catch(error => {
counter++;
resultArr[i] = { staus: "status", reason: error };
resolve(resultArr);
});
}
});
};
- 测试用例
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, "foo"));
const promises = [promise1, promise2];
Promise.allSettled(promises).then(results => results.forEach(result => console.log(result)));
结果: