在介绍promise之前我们先看一道面试题。
console.log(1)
const test = () => {
console.log(3)
return 4
}
const promise = new Promise((resole, reject) => {
console.log(2)
resole(test())
})
promise.then(res => {
console.log(res)
})
console.log(5)
答案为: 1 2 3 5 4 从答案我们可以看出promise本身是一个同步函数,其原型上的then方法才是异步执行的。 我们都知道promise的出现解决了ajax回调地狱的问题,那为什么promis可以解决回调地狱问题呢?接下来通过从0到1实现promise来理解这一问题。
手写开始
我们先分析一下promise的基本原理
- Promise本质上是一个构造函数, 在执行这个构造函数传入一个函数执行器,并且该执行器会立即执行。
- promise内部维护三个状态,且状态不可逆。pengding -> Fulfilled、pengding -> Rejected
- Pending 等待
- Fulfilled 完成
- Rejected 失败
- Promise 中使用 resolve 和 reject 两个函数来更改状态;
1、下面开始实现
// 先定义三个状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise{
// executor: 传入的执行器函数,会立即执行
constructor(executor) {
this.value = null; // 接收成功的值
this.reason = null; // 接受失败的原因
this.status = PENDING; // 初始状态
executor(this.resolve, this.reject) // 执行器执行
}
// 这里需要用箭头函数,要不拿不到this
resolve = (value) => {
if(this.status !== PENDING) return ; // 只有状态为等待才能修改
this.status = FULFILLED; // 状态改为成功
this.value = value; // 保存成功的值
}
// 这里需要用箭头函数,要不拿不到this
reject = (reason) => {
if(this.status !== PENDING) return ; // 只有状态为等待才能修改
this.status = REJECTED; // 状态改为失败
this.reason = reason; // 保存失败的值
}
then(onFulfilled, onRejected) {
if(this.status === FULFILLED) {
onFulfilled(this.value)
} else if(this.status === REJECTED){
onRejected(this.reason)
}
}
}
// 测试
const promise = new MyPromise((resole, reject) => {
resole('执行成功回调')
})
promise.then((res) => {
console.log(res)
}, (err) => {
console.log(err)
})
2、加入异步逻辑
上面写的都是同步的逻辑,then函数也是异步的,所以接下来我们开始增加异步逻辑代码。
// 测试
const promise = new MyPromise((resole, reject) => {
setTimeout(() => {
resole('执行成功回调')
}, 0) // 这里改成异步
})
promise.then((res) => {
console.log(res)
}, (err) => {
console.log(err)
})
上述代码执行是不会打印“执行成功回调”的,这是因为当执行原型上的then方法时,状态还是PENDING。所以此时我们应该把then传入的方法储存起来,等到状态改变之后再去执行。
constructor(executor) {
this.value = null; // 接收成功的值
this.reason = null; // 接受失败的原因
this.status = PENDING; // 初始状态
+this.onFulfilledCallback = []; // 储存成功的回调
+this.onRejectedCallback = []; // 存储失败的回调
executor(this.resolve, this.reject) // 执行器执行
}
改造resolve、reject方法
resolve = (value) => {
if(this.status !== PENDING) return ; // 只有状态为等待才能修改
this.status = FULFILLED; // 状态改为成功
this.value = value; // 保存成功的值
+this.onFulfilledCallback.forEach(callback => callback()); // 状态改变,执行onFulfilledCallback数组储存的函数
}
reject = (reason) => {
if(this.status !== PENDING) return ; // 只有状态为等待才能修改
this.status = REJECTED; // 状态改为失败
this.reason = reason; // 保存失败的值
+this.onRejectedCallback.forEach(callback => callback()); // 状态改变,执行onRejectedCallback数组储存的函数
}
改造then方法
then(onFulfilled, onRejected) {
if(this.status === FULFILLED) {
setTimeout(() => { // then是异步的
onFulfilled(this.value); // 执行成功的回调
}, 0)
} else if(this.status === REJECTED){
setTimeout(() => { // then是异步的
onRejected(this.reason); // 执行失败的回调
}, 0)
}else{
// 当状态为Pending是分别用onFulfilledCallback、onRejectedCallback储存成功、失败的回调
this.onFulfilledCallback.push(() => {
setTimeout(() => {
onFulfilled(this.value); // 执行成功的回调
}), 0
})
this.onRejectedCallback.push(() => {
setTimeout(() => {
onRejected(this.reason); // 执行失败的回调
}, 0)
})
}
}
3、promise的then方法可以链式调用(因此其应该返回一个promise实例,事实上promise的其它方法如:原型上的catch,静态方法all,race,resole,reject,allSettled,等等都应该返回一个新的promise实例,下文会一一介绍)
改造then方法
then(onFulfilled, onRejected) {
// 实现then链式调用
const resPromise = (p, s, resolve, reject) => {
if(p === s) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
if(s instanceof MyPromise) {
s.then(resolve, reject)
}else{
resolve(s)
}
}
let promise = new MyPromise((resolve, reject) => {
if(this.status === FULFILLED) {
setTimeout(() => { // then是异步的
let s = onFulfilled(this.value) // 执行成功的回调, 并且接受上一个promise成功回调返回的值
resPromise(promise, s, resolve, reject)
}, 0)
} else if(this.status === REJECTED){
setTimeout(() => { // then是异步的
let s = onRejected(this.reason) // 执行失败的回调,并且接受上一个promise失败回调返回的值
resPromise(promise, s, resolve, reject)
}, 0)
}else{
this.onFulfilledCallback.push(() => {
setTimeout(() => {
let s = onFulfilled(this.value); // 执行成功的回调
resPromise(promise, s, resolve, reject)
}), 0
})
this.onRejectedCallback.push(() => {
setTimeout(() => {
let s = onRejected(this.reason); // 执行失败的回调
resPromise(promise, s, resolve, reject)
}, 0)
})
}
})
return promise
}
}
4、promise其它方法的实现(基于上述实现的then方法实现)
1、原型方法catch的实现
catch(onRejected) {
return this.then(undefined, onRejected)
}
2、静态方法resolve、reject
static resolve(value) {
return new MyPromise((resolve, reject) => {
if(resolve instanceof MyPromise) {
value.then(resolve, reject)
}else {
resolve(value)
}
})
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
resolve(reason)
})
}
3、静态方法all、race
all,race两个方法都接收一个数组,all需要数组内所有的promise都成功才会返回成功的值,该值是所有实例的成功之后值的集合,race返回的是最先完成的promise实例的值,无论成功与否
static all(promises) {
let len = promises.length;
let arr = []
promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p)); // 不是promise实例就先转化为promise实例
return new MyPromise((resolve, reject) => {
for(let i = 0; i < len; i++) {
promises[i].then(res => {
arr[i] = res;
if(arr.length === len) { // 等promises数组所有的实例都返回成功,才resolve
resolve(arr);
}
}, (err) => {
reject(err); // 只要有一个实例失败,就返回失败
})
}
})
}
static race(promises) {
let len = promises.length;
promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p));
return new MyPromise((resolve, reject) => {
for(let i = 0; i < len; i++) {
promises[i].then((res) => resolve(res), (err) => reject(err)); // 无论成功与否,只返回第一个完成的promise
}
})
}
4、静态方法allSettled
allSettled也是接受一个数组,但与all不一样的是,它返回的是数组所有promise返回值的集合。
static allSettled(promises) {
let len = promises.length;
let arr = []
promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p));
return new MyPromise((resolve, reject) => {
for(let i = 0; i < len; i++) {
promises[i].then((res) => {
arr[i] = {
status: 'fulfilled',
value: res
}
if(arr.length === len) resolve(arr); // 当数组遍历完才更改promise状态为成功
}, (err) => {
arr[i] = {
status: 'rejected',
value: err
};
if(arr.length === len) resolve(arr); // 当数组遍历完才更改promise状态为成功
})
}
})
}
5、静态方法any
该方法也是接受一个数组,与all方法相反,它只要有一个promise状态为fulfilled就返回成功状态,当所有的promise都失败才会返回失败的状态。
static any(promises) {
let len = promises.length;
let arr = []
promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p));
for(let i = 0; i < len; i++) {
promises[i].then(res => {
resolve(res); // 只要有一个promise成功,就resole,返回成功状态
}, (err) => {
arr[i] = err;
if(arr.length === len) { // 等promises数组所有的实例都返回失败,才reject, 返回失败状态
reject(arr);
}
})
}
}
完整代码
// console.log(1)
// const test = () => {
// console.log(3)
// return 4
// }
// const promise = new Promise((resole, reject) => {
// console.log(2)
// resole(test())
// })
// promise.then(res => {
// console.log(res)
// })
// console.log(5)
// 先定义三个状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise{
// executor: 传入的执行器函数,会立即执行
constructor(executor) {
this.value = null; // 接收成功的值
this.reason = null; // 接受失败的原因
this.status = PENDING; // 初始状态
this.onFulfilledCallback = []; // 储存成功的回调
this.onRejectedCallback = []; // 存储失败的回调
executor(this.resolve, this.reject) // 执行器执行
}
resolve = (value) => {
if(this.status !== PENDING) return ; // 只有状态为等待才能修改
this.status = FULFILLED; // 状态改为成功
this.value = value; // 保存成功的值
this.onFulfilledCallback.forEach(callback => callback()); // 状态改变,执行onFulfilledCallback数组储存的函数
}
reject = (reason) => {
if(this.status !== PENDING) return ; // 只有状态为等待才能修改
this.status = REJECTED; // 状态改为失败
this.reason = reason; // 保存失败的值
this.onRejectedCallback.forEach(callback => callback()); // 状态改变,执行onRejectedCallback数组储存的函数
}
then(onFulfilled, onRejected) {
const resPromise = (p, s, resolve, reject) => {
if(p === s) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
if(s instanceof MyPromise) {
s.then(resolve, reject)
}else{
resolve(s)
}
}
let promise = new MyPromise((resolve, reject) => {
if(this.status === FULFILLED) {
setTimeout(() => { // then是异步的
let s = onFulfilled(this.value);
resPromise(promise, s, resolve, reject); // 执行成功的回调
}, 0)
} else if(this.status === REJECTED){
setTimeout(() => { // then是异步的
let s = onRejected(this.reason);
resPromise(promise, s, resolve, reject); // 执行失败的回调
}, 0)
}else{
this.onFulfilledCallback.push(() => {
setTimeout(() => {
let s = onFulfilled(this.value); // 执行成功的回调
resPromise(promise, s, resolve, reject);
}), 0
})
this.onRejectedCallback.push(() => {
setTimeout(() => {
let s = onRejected(this.reason); // 执行失败的回调
resPromise(promise, s, resolve, reject);
}, 0)
})
}
})
return promise;
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
static resolve(value) {
return new MyPromise((resolve, reject) => {
if(resolve instanceof MyPromise) {
value.then(resolve, reject);
}else {
resolve(value);
}
})
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
resolve(reason);
})
}
static all(promises) {
let len = promises.length;
let arr = []
promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p)); // 不是promise实例就先转化为promise实例
return new MyPromise((resolve, reject) => {
for(let i = 0; i < len; i++) {
promises[i].then(res => {
arr[i] = res;
if(arr.length === len) { // 等promises数组所有的实例都返回成功,才resolve
resolve(arr);
}
}, (err) => {
reject(err); // 只要有一个实例失败,就返回失败
})
}
})
}
static race(promises) {
let len = promises.length;
promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p));
return new MyPromise((resolve, reject) => {
for(let i = 0; i < len; i++) {
promises[i].then((res) => resolve(res), (err) => reject(err)) // 无论成功与否,只返回第一个完成的promise
}
})
}
static allSettled(promises) {
let len = promises.length;
let arr = []
promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p));
return new MyPromise((resolve, reject) => {
for(let i = 0; i < len; i++) {
promises[i].then((res) => {
arr[i] = {
status: 'fulfilled',
value: res
}
if(arr.length === len) resolve(arr); // 当数组遍历完才更改promise状态为成功
}, (err) => {
arr[i] = {
status: 'rejected',
value: err
};
if(arr.length === len) resolve(arr); // 当数组遍历完才更改promise状态为成功
})
}
})
}
static any(promises) {
let len = promises.length;
let arr = []
promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p));
for(let i = 0; i < len; i++) {
promises[i].then(res => {
resolve(res); // 只要有一个promise成功,就resole,返回成功状态
}, (err) => {
arr[i] = err;
if(arr.length === len) { // 等promises数组所有的实例都返回失败,才reject, 返回失败状态
reject(arr);
}
})
}
}
}
// 测试
const promise = new MyPromise((resole, reject) => {
// resole('执行成功回调')
reject('执行失败回调')
})
// promise.then((res) => {
// console.log(res)
// return '链式调用'
// }, (err) => {
// console.log(err)
// }).then((res) => {
// console.log(res)
// })
// console.log('22222222')
// promise.catch((err) => {
// console.log(err)
// return 2112
// }).then(res => {
// console.log(res)
// })