文章目录
- 前言
- 一、前置知识
- 二、实现基本功能
- 二、实现链式调用
- 三、实现Promise.all
- 四、实现Promise.race
- 总结
前言
关于动机,无论是在工作还是面试中,都会遇到Promise的相关使用和原理,手写Promise也有助于学习设计模式以及代码设计。
本文主要介绍了如何使用自己的代码去实现Promise的一些功能。
以下是本篇文章正文内容
一、前置知识
手写之前,需要知道promise有哪些基本特性:
1、promise有三种状态:pending、fulfilled、rejected。
2、promise的默认状态是pending,状态流转有两种:pending—>fulfilled、pending—>rejected。
3、实例化Promise时,可以接收一个函数作为参数,这个函数有两个参数,分别是resolve、reject方法用于改变实例状态。并能够执行下一个then中的回调函数。
4、then方法中接收两个函数作为参数,第一个函数相当于执行上一个 promise 中执行 resolve 后对应的回调,第二个函数相当于执行上一个 promise 中执行 reject 后对应的回调。
// 1. 实例化 Promise 时
// 可以接收一个函数作为参数,这个函数可以接收到 resolve 和 reject 两个实例方法
// 用于更改当前实例的状态,并把它们接收到的参数传递给下一个 then 对应的参数中
new Promise((resolve, reject) => {
// resolve 和 reject 可以都执行,但都执行的意义不大,因为 promise 状态发生更改后,就不能在被更改
resolve('ok');
// reject('err');
}).then((value) => {
console.log("resolve callback = ", value); // 若执行 resolve,则 value = ok
}, (reason) => {
console.log("reject callback = ", reason); // 若执行 reject,则 value = err
});
5、then操作后会返回一个新的Promise,且支持链式调用。
let promise = new Promise((resolve,reject) => {
resolve(11)
})
const a = new Promise((resolve,reject) => {
reject('ok')
})
promise.then(res => {
console.log(res)
return a
}).then(res => console.log(res))
6、Promise.all以数组的形式接收多个Promise,当所有Promise执行完成,且状态都为fulfilled时,返回执行成功的结果;有一个失败,则返回失败的结果。
7、Promise.race以数组的形式接收多个Promise,只要有一个Promise先执行成功,无论什么状态,都返回这个结果,给到下一个then中对应的回调。
二、实现基本功能
1、
- new 操作
- resolve、reject方法
- then方法
// 定义三种状态
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
// 1、默认状态 - PENDING
this.status = PENDING;
// 2、内部维护的变量值
this.value = undefined;
this.reason = undefined;
try {
executor(this.resolve.bind(this), this.reject.bind(this)) // 实例化传进来的函数会立即执行
} catch(err) {
this.reject(err)
}
}
resolve(value) {
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
}
}
reject(reason) {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
}
}
then(onFulfilled, onRejected) {
if (onFulfilled && this.status === FULFILLED) {
let res = onFulfilled(this.value)
this.resolvePromise(res, resolve, reject)
}
if (onRejected && this.status === REJECTED) {
let res = onRejected(this.reason)
this.resolvePromise(res, resolve, reject)
}
}
}
通过以下代码自测:
new Promise((resolve,reject) => {
resolve(1)
}).then(res=> {
console.log(res) // 1
})
2、考虑异步的情况。
以上代码都是同步的,Promise实例化时传入了异步函数如setTimeout,在setTimeout中resolve,在下一个then的回调函数获取异步函数的状态呢?
我们可以使用回调队列缓存起来,等待执行:
// 定义三种状态
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
// 1、默认状态 - PENDING
this.status = PENDING;
// 2、内部维护的变量值
this.value = undefined;
this.reason = undefined;
this.onResolveCallBack = [];// 缓存 onResolve
this.onRejectCallBack = [];// 缓存 onReject
try {
executor(this.resolve.bind(this), this.reject.bind(this)) // 实例化传进来的函数会立即执行
} catch(err) {
this.reject(err)
}
}
resolve(value) {
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
// 遍历调用 onResolveCallBack
this.onResolveCallBack.forEach(fn => fn());
}
}
reject(reason) {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
this.onResolveCallBack.forEach(fn => fn());
}
}
then(onFulfilled, onRejected) {
if (onFulfilled && this.status === FULFILLED) {
let res = onFulfilled(this.value)
this.resolvePromise(res, resolve, reject)
}
if (onRejected && this.status === REJECTED) {
let res = onRejected(this.reason)
this.resolvePromise(res, resolve, reject)
}
// 当前 promise 状态为 pending,把当前的 onResolve & onReject 缓存起来
if (this.status === PENDING) {
this.onResolveCallBack.push(() => {
onResolve(this.value);
});
this.onRejectCallBack.push(() => {
onReject(this.value);
});
}
}
}
用以下代码测试通过:
let p = new MyPromise((resolve, reject) => {
setTimeout(()=>{
resolve(1);
},1000);
}).then(value => {
console.log('then resolve = ', value);
}, reason => {
console.log('then reject = ', reason);
});
// then resolve = 1
二、实现链式调用
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => { // 支持链式调用
if (onFulfilled && this.status === FULFILLED) {
let res = onFulfilled(this.value)
resolve(res);
}
if (onRejected && this.status === REJECTED) {
let res = onRejected(this.reason)
resolve(res);
}
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() =>{
let res = onFulfilled(this.value)
resolve(res);
})
this.onRejectedCallbacks.push(() => {
let res = onRejected(this.reason)
resolve(res);
})
}
})
}
测试用例:
let promise = new Promise((resolve,reject) => {
resolve(1)
})
promise.then(res => {
return 2 // 返回普通对象
}).then(res => console.log(res)) // 2
如果在then中返回的是普通对象,上述代码能满足,如果返回的是一个Promise,则还需要补充:
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => { // 支持链式调用
if (onFulfilled && this.status === FULFILLED) {
let res = onFulfilled(this.value)
this.resolvePromise(res, resolve, reject)
}
if (onRejected && this.status === REJECTED) {
let res = onRejected(this.reason)
this.resolvePromise(res, resolve, reject)
}
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() =>{
let res = onFulfilled(this.value)
this.resolvePromise(res, resolve, reject)
})
this.onRejectedCallbacks.push(() => {
let res = onRejected(this.reason)
this.resolvePromise(res, resolve, reject)
})
}
})
}
resolvePromise(res, resolve, reject) {
if(res instanceof Promise) { // 对then中返回Promise做处理
res.then(resolve, reject)
} else{
// 普通值
resolve(res)
}
}
测试用例:
let promise = new Promise((resolve,reject) => {
resolve(11)
})
const a = new Promise((resolve,reject) => {
reject('ok')
})
promise.then(res => {
return a;
}).then(res => console.log(res)) // ok
三、实现Promise.all
由上述前置知识可知,Promise.all是全部成功才返回成功的结果,有一个失败就返回失败的结果:
Promise.all = function(arr) {
return new Promise((resolve, reject) => {
if (!Array.isArray(arr)) {
return reject("参数必须为数组");
}
let successNum = 0; // 成功的Promise条数
let resultArray = [];
let totalNum = arr.length; // 总Promise数量
let isFail = false;
arr.forEach(item => {
item.then(res => {
successNum++;
resultArray.push(res);
if (successNum === totalNum) { // 说明是全部成功
return resolve(resultArray)
}
}, err => {
if (!isFail) reject(err)
isFail = true;
})
});
})
}
测试用例:
function wait500(input) {
return new Promise((resolve, reject) => {
setTimeout(()=> {
resolve(500)
}, 500)
})
}
function wait1000(input) {
return new Promise((resolve, reject) => {
setTimeout(()=> {
resolve(1000)
}, 1000)
})
}
// 全部执行完成之后回调
Promise.all([wait1000(), wait500()]).then(result => {
console.log('all end', result)
}, err => {
console.log('fafaf', err)
}) // 'all end [500, 1000]'
四、实现Promise.race
由上述前置知识可知,Promise.race是有一个promise先执行成功,无论什么状态,都返回这个结果:
Promise.race = function(arr) {
return new Promise((resolve, reject) => {
if (!Array.isArray(arr)) {
return reject("参数必须为数组");
}
arr.forEach(item => {
item.then(res => {
return resolve(res); // 状态不可逆,只要其中一个Promise转变了状态,后续状态就不会发生改变
}, err => {
reject(err);
})
});
})
}
测试用例:
function wait500(input) {
return new Promise((resolve, reject) => {
setTimeout(()=> {
resolve(500)
}, 500)
})
}
function wait1000(input) {
return new Promise((resolve, reject) => {
setTimeout(()=> {
resolve(1000)
}, 1000)
})
}
Promise.race([wait1000(), wait500()]).then(result => {
console.log('all end', result)
}, err => {
console.log('fafaf', err)
}) // 打印出'all end 500'
总结
总的代码:
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
// 1、默认状态 - PENDING
this.status = PENDING;
// 2、内部维护的变量值
this.value = undefined;
this.reason = undefined;
// 存放回调
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch(err) {
this.reject(err)
}
}
resolve(value) {
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
this.onResolvedCallbacks.forEach(fn => fn())
}
}
reject(reason) {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
this.onRejectedCallbacks.forEach(fn => fn())
}
}
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => { // 支持链式调用
if (onFulfilled && this.status === FULFILLED) {
let res = onFulfilled(this.value)
this.resolvePromise(res, resolve, reject)
}
if (onRejected && this.status === REJECTED) {
let res = onRejected(this.reason)
this.resolvePromise(res, resolve, reject)
}
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() =>{
let res = onFulfilled(this.value)
this.resolvePromise(res, resolve, reject)
})
this.onRejectedCallbacks.push(() => {
let res = onRejected(this.reason)
this.resolvePromise(res, resolve, reject)
})
}
})
}
resolvePromise(res, resolve, reject) {
if(res instanceof Promise) {
res.then(resolve, reject)
} else{
// 普通值
resolve(res)
}
}
}
// 全部成功才返回成功的结果,有一个失败就返回失败的结果
Promise.all = function(arr) {
return new Promise((resolve, reject) => {
if (!Array.isArray(arr)) {
return reject("参数必须为数组");
}
let successNum = 0;
let resultArray = [];
let totalNum = arr.length;
let isFail = false;
arr.forEach(item => {
item.then(res => {
successNum++;
resultArray.push(res);
if (successNum === totalNum) {
return resolve(resultArray)
}
}, err => {
if (!isFail) reject(err)
isFail = true;
})
});
})
}
// 某个promise先完成,
Promise.race = function(arr) {
return new Promise((resolve, reject) => {
if (!Array.isArray(arr)) {
return reject("参数必须为数组");
}
arr.forEach(item => {
item.then(res => {
return resolve(res);
}, err => {
reject(err);
})
});
})
}