说到Promise
,肯定首先想起它的作用—— 异步编程解决方案。出于更为深刻理解它的原因,我尝试手写了一下它的一部分功能的源码。
首先,讲一下promise的两个核心方法resolve
和reject
,它的作用是改变promise对象的状态(resolve:pending --> fulfilled,reject:pending --> rejected),也就是说promise仅有一次更改状态的可能。
- resolve&reject方法源码
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor){
executor(this.resolve,this.reject)//执行器立即执行 --》这个执行器指的是调用promise的回调函数
}
status = PENDING
resolve = () => {
if(this.status !== PENDING) return
this.status = FULFILLED//更改状态为成功
}
reject = () => {
if(this.status !== PENDING) return
this.status = REJECTED//更改状态为失败
}
}
其次,关于then
方法,其实就是一个根据状态执行不同回调函数的方法。但是状态的确定,并不一定是同步的,比如可能是根据请求某个后台接口的数据而确定调用resolve或者reject方法,此时,我们就需要兼容异步情况。
- then方法源码
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject); //执行器立即执行 --》这个执行器指的是调用promise的回调函数
}
status = PENDING;
value = undefined;
reason = undefined;
successCallBack = [];
failCallBack = [];
resolve = (value) => {
if (this.status !== PENDING) return;
this.status = FULFILLED; //更改状态为成功
this.value = value; //保存成功之后的值
while (this.successCallBack.length) this.successCallBack.shift()(this.value); //存在成功回调则调用
};
reject = (reason) => {
if (this.status !== PENDING) return;
this.status = REJECTED; //更改状态为失败
this.reason = reason; //保存失败之后的值
while (this.failCallBack.length) this.failCallBack.shift()(this.reason);//存在失败回调则调用
};
then(successCallBack, failCallBack) {
if (this.status === FULFILLED) {
successCallBack(this.value);
} else if (this.status === REJECTED) {
failCallBack(this.reason);
} else {
//异步情况 暂时储存 需要时再调用
this.successCallBack.push(successCallBack);
this.failCallBack.push(failCallBack);
}
}
}
module.exports = MyPromise;
promise还有一个显著特征,then方法的链式调用。原因是因为每次then方法执行完,都会返回一个人新的promise对象,所以它能继续调用下去。
- then方法的链式调用源码
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject); //执行器立即执行 --》这个执行器指的是调用promise的回调函数
}
status = PENDING;
value = undefined;
reason = undefined;
successCallBack = [];
failCallBack = [];
resolve = (value) => {
if (this.status !== PENDING) return;
this.status = FULFILLED; //更改状态为成功
this.value = value; //保存成功之后的值
while (this.successCallBack.length)
this.successCallBack.shift()(this.value); //存在成功回调则调用
};
reject = (reason) => {
if (this.status !== PENDING) return;
this.status = REJECTED; //更改状态为失败
this.reason = reason; //保存失败之后的值
while (this.failCallBack.length) this.failCallBack.shift()(this.reason); //存在失败回调则调用
};
then(successCallBack, failCallBack) {
let newPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
let x = successCallBack(this.value);
// resolve(x);
resolvePromise(x, resolve, reject);
} else if (this.status === REJECTED) {
failCallBack(this.reason);
} else {
//异步情况 暂时储存 需要时再调用
this.successCallBack.push(successCallBack);
this.failCallBack.push(failCallBack);
}
});
return newPromise;
}
}
function resolvePromise(x, resolve, reject) {
if (x instanceof MyPromise) {
//promise 对象
x.then(resolve, reject);
} else {
//普通值
resolve(x);
}
}
module.exports = MyPromise;
- 基础使用
const myPromise = require("./myPromise.js");
const p = new myPromise((resolve, reject) => {
resolve("success");
// reject("fail");
});
p.then(value => {
console.log(value);
return 10
},reason => console.log(reason)
).then(value => console.log(value))
下面附上部分其他功能(all\resolve\catch)源码
//1 接收一个执行器,并立即执行
//2 resolve、reject改变状态
//3 状态一旦改变不可更改
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
constructor(executor){//1
try {//捕获错误
executor(this.resolve,this.reject)
} catch (error) {
this.reject(error)
}
}
status = PENDING//初始化promise状态
value = undefined//成功回调的值
reason = undefined//失败回调的原因
// successCallBack = undefined // 成功回调 用于异步情况暂存回调函数
// failCallBack = undefined // 失败回调 用于异步情况暂存回调函数
successCallBack = []//兼容then函数里面有多个异步回调
failCallBack = []//兼容then函数里面有多个异步回调
resolve = value =>{//2
if(this.status !== PENDING)return//3
this.status = FULFILLED
this.value = value
//异步回调执行
// this.successCallBack&&this.successCallBack(this.value)
while(this.successCallBack.length){//兼容then函数里面有多个异步回调 每执行完一个回调则删除当前函数项
// this.successCallBack.shift()(this.value)
this.successCallBack.shift()()//then里已经执行完回调并把结果包在函数中 等异步执行接受取出结果即可
}
}
reject = reason =>{//2
if(this.status !== PENDING)return//3
this.status = REJECTED
this.reason = reason
//异步回调执行
// this.failCallBack&&this.failCallBack(this.reason)
while(this.failCallBack.length){//兼容then函数里面有多个异步回调 每执行完一个回调则删除当前函数项
// this.failCallBack.shift()(this.reason)
this.failCallBack.shift()()//then里已经执行完回调并把结果包在函数中 等异步执行接受取出结果即可
}
}
then = (successCallBack,failCallBack) =>{
successCallBack= successCallBack || (value => value)//兼容then可选传参情况
failCallBack= failCallBack || (reason => {throw reason})//兼容then可选传参情况
let promise2 = new MyPromise((resolve,reject)=>{
if(this.status === FULFILLED){
try {
setTimeout(()=>{
let x = successCallBack(this.value) //成功回调 x为返回值 链式调用中上一个then方法会返回一个值给下一个then方法
// resolve(x)
//判断x的值是普通值还是promise对象
//如果是普通值 直接调用resolve
//如果是promise对象 查看promise对象返回的结果
//再根据promise对象返回的结果 决定调用resolve 还是 reject
resolvePromise(promise2,x,resolve,reject)
},0)
} catch (error) {
reject(error)
}
}else if(this.status === REJECTED){
try {
setTimeout(()=>{
let x = failCallBack(this.reason)//失败回调
resolvePromise(promise2,x,resolve,reject)
},0)
} catch (error) {
reject(error)
}
// failCallBack(this.reason)//失败回调
}else{
//异步情况 存着异步执行代码时 this.status为PENDING
// this.successCallBack = successCallBack
// this.failCallBack = failCallBack
// this.successCallBack.push(successCallBack)
// this.failCallBack.push(failCallBack)
this.successCallBack.push(()=>{
try {
setTimeout(()=>{
let x = successCallBack(this.value)
resolvePromise(promise2,x,resolve,reject)
},0)
} catch (error) {
reject(error)
}
})
this.failCallBack.push(()=>{
try {
setTimeout(()=>{
let x = failCallBack(this.reason)
resolvePromise(promise2,x,resolve,reject)
},0)
} catch (error) {
reject(error)
}
})
}
})//兼容promise的链式调用-》每个then必须返回一个promise对象,后面的调用链才能调用then方法
return promise2
}
finally = (callback) =>{
return this.then(value =>{
// callback()
// return value
//为了兼容finally中异步代码
return MyPromise.resolve(callback()).then(()=>value)
},reason =>{
// callback()
// throw reason
return MyPromise.resolve(callback()).then(()=>{throw reason})
})
}
catch = (failCallBack) =>{
return this.then(undefined,failCallBack)
}
static all(array) {
let result = []
let index = 0
return new MyPromise((resolve,reject) =>{
function addData(key,value){
result[key]=value
index++
if(index === array.length){//异步情况下,保证所有异步代码执行完毕再抛出result
resolve(result)
}
}
for(let i = 0; i<array.length;i++){
if(array[i] instanceof MyPromise){
//promise对象
let current = array[i]
current.then(value =>addData(i,value),reason => reject(reason))
}else{
//普通值
addData(i,array[i])
}
}
})
}
static resolve(value){
if(value instanceof MyPromise) return value //如果是promise对象 直接返回供promise调用链执行
return new MyPromise(resolve => resolve(value))//如果是普通值 需要包一层promise对象
}
}
function resolvePromise (promise2,x,resolve,reject){
if(x === promise2){
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if(x instanceof MyPromise){
//promise对象
// x.then(value =>{resolve(value)},reason =>{reject(reason)})
x.then(resolve,reject)
}else{
//普通值
resolve(x)
}
}
module.exports = MyPromise