下面是一个用于面试的简单版的Promise
function MyPromise(executor){
if(typeof executor !== 'function') throw new Error('请传入执行器函数executor 例如function(resolve,reject){}')//必须传入executor函数,如果不传是会报错的
let self = this;//保存this
self.status = 'pending';//promise总共有三种状态,pending、fulfilled、reject,一旦状态改变就不可逆转,(很多面试管都喜欢问你当pending变为fulfilled之后还能变成reject?)
self.value = null;//用于保存结果值
self.onResolveCallBack = [];//当resolve在异步中执行的时候,用于保存then中要执行的函数,让resolve的时候在遍历执行里面的函数
self.onRejectCallBack = [];//reject同上(resolve)
function resolve(value){//resolve函数
if(self.status === 'pending'){
self.status = 'fulfilled'//进来之后就改变stauts的状态,这就是为什么status状态是不可逆的,(self.status === 'pending')
self.value = value
self.onResolveCallBack.forEach(fn => fn())//用于异步resolve执行then中的回调
}
}
function reject(value) {//同上(resolve)
if(self.status === 'pending'){
self.status = 'reject';
self.value = value;
self.onRejectCallBack.forEach(fn => fn())
}
}
try {
executor(resolve,reject)//promise的执行器,放在try中防止出错
} catch (error) {
throw new Error(error)
}
}
MyPromise.prototype.then = function (fn1,fn2) {//fn1是成功的时候执行的,fn2是失败的时候执行和catch捕获的是一样的
let self = this;
// 根据规范,如果then的参数不是function,则我们需要忽略它, 让链式调用继续往下执行
typeof fn1 === 'function' ? null : fn1 = (value) => value;
typeof fn2 === 'function' ? null : fn2 = (reason) =>{
throw new Error(reason instanceof Error ? reason.message : reason)
}
return new MyPromise((resolve,reject)=> {//promise可以链式调用就是因为then中重新返回一个promise
if(self.status === 'fulfilled'){//当成功的时候执行fn1
try {
let result = fn1(self.value)
resolve(result) //用于下个then
} catch (error) {
reject(error)
}
}
if(self.status === 'reject'){//当失败的时候执行
try {
if(typeof fn2 === 'function'){//如果then中没有传第二个函数就把value值直接放入reject用于后面的catch捕获
let result = fn2(self.value);
reject(result)
}else{
reject(self.value)
}
} catch (error) {
reject(error)
}
}
//如果是pending说明执行器executor中的resolve() 在异步中执行的,我们
//就把then中的回调函数放入onResolveCallBack当执行resolve()的时候拿到value值之后,在去遍历
if(self.status === 'pending'){
self.onResolveCallBack.push(()=>{
let result = fn1(self.value);
resolve(result)
})
self.onRejectCallBack.push(()=>{
let result = fn2(self.value);
resolve(result)
})
}
})
}
MyPromise.prototype.catch = function(errFn) {//类似于then,只要处理错误回调就行了
return this.then(undefined, errFn)
}
MyPromise.isPromise = function(value) {//简单判断是否是个Promise函数
return typeof value.then === 'function'
}
MyPromise.all = function(value) {//简单实现promise中all方法
let self =this;
if(!Array.isArray(value)){
throw new Error('value is not array')
}
if(value.length === 0){
return []
}
return new MyPromise(function(resolve,reject){//all方法返回的是个promise
let result = [];
let count = 0;//用于计数,当value的长度和count相等就resolve,也是all方法比较核心的地方
for(let i = 0; i<value.length; i++){
let currentV = value[i]
let isPromise = MyPromise.isPromise(currentV);
if(isPromise){
currentV.then(res =>{
count++
result[i] = res;
if(count === value.length)return resolve(result)
},err=>{
reject(err,9999)
}).catch(err=> {
reject(err)
})
} else{
count++
result[i] = currentV;
if(count === value.length)return resolve(result)
}
}
})
}
MyPromise.reac = function (value) {
if(!Array.isArray(value)){throw new Error('请传入一个array')}
return new MyPromise((resolve,reject)=>{
for(let i = 0; i<value.length; i++){
let currentV = value[i];
if(MyPromise.isPromise(currentV)){
currentV.then(res =>{
resolve(res)
})
}else {
resolve(currentV)
}
}
})
}
MyPromise.resolve = function(value) {
return new MyPromise((resolve,reject) => {
resolve(value)
})
}
MyPromise.reject = function(value) {
return new MyPromise((resolve,reject)=> {
reject(value)
})
}
// let test = new MyPromise(function(resolve,reject){
// setTimeout(() => {
// resolve(222)
// }, 2000);
// })
// test.then(res=>{
// console.log(res)
// })
// let isPromise = MyPromise.isPromise(new MyPromise(function(){}));
// console.log(isPromise,'isPromise')
// let myP = new MyPromise(() =>{})
// console.log(myP)
let p1 = new MyPromise((resolve,reject)=>{ reject(1)})
let p2 = new MyPromise((resolve,reject)=>{ resolve(2)})
let p3 = new MyPromise((resolve,reject)=>{ resolve(3)})
let p4 = new MyPromise((resolve,reject)=>{ resolve(4)})
let p5 = new MyPromise((resolve,reject)=>{ resolve(5)})
MyPromise.all([p1,p2,p3,p4,p5,99]).then(res =>{
console.log(res)
}).catch(err =>{
console.log(err,999)
})
// MyPromise.reac([34234,p1]).then((res) =>{
// console.log(res,'reac')
// })
// MyPromise.resolve(4444555).then(res=> {
// console.log(res,'resolve')
// return 'test'
// }).then(res =>{
// console.log(res,'8866')
// })
// console.log(MyPromise.prototype.constructor.name,'78whidfgdgkjdh')
let myP = new MyPromise(function(resolve,reject){
// reject(1)
setTimeout(() => {
reject(1)
}, 1000);
})
myP.then(res=> {
console.log(res,8888)
}).catch((err)=>{
console.log(err,'console.error();')
})
clas类写法
//Promise/A+规定的三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
// 构造方法接收一个回调
constructor(executor) {
this._status = PENDING // Promise状态
this._value = undefined // 储存then回调return的值
this._resolveQueue = [] // 成功队列, resolve时触发
this._rejectQueue = [] // 失败队列, reject时触发
// 由于resolve/reject是在executor内部被调用, 因此需要使用箭头函数固定this指向, 否则找不到this._resolveQueue
let _resolve = (val) => {
//把resolve执行回调的操作封装成一个函数,放进setTimeout里,以兼容executor是同步代码的情况
const run = () => {
if(this._status !== PENDING) return // 对应规范中的"状态只能由pending到fulfilled或rejected"
this._status = FULFILLED // 变更状态
this._value = val // 储存当前value
// 这里之所以使用一个队列来储存回调,是为了实现规范要求的 "then 方法可以被同一个 promise 调用多次"
// 如果使用一个变量而非队列来储存回调,那么即使多次p1.then()也只会执行一次回调
while(this._resolveQueue.length) {
const callback = this._resolveQueue.shift()
callback(val)
}
}
setTimeout(run)
}
// 实现同resolve
let _reject = (val) => {
const run = () => {
if(this._status !== PENDING) return // 对应规范中的"状态只能由pending到fulfilled或rejected"
this._status = REJECTED // 变更状态
this._value = val // 储存当前value
while(this._rejectQueue.length) {
const callback = this._rejectQueue.shift()
callback(val)
}
}
setTimeout(run)
}
// new Promise()时立即执行executor,并传入resolve和reject
executor(_resolve, _reject)
}
// then方法,接收一个成功的回调和一个失败的回调
then(resolveFn, rejectFn) {
// 根据规范,如果then的参数不是function,则我们需要忽略它, 让链式调用继续往下执行
typeof resolveFn !== 'function' ? resolveFn = value => value : null
typeof rejectFn !== 'function' ? rejectFn = reason => {
throw new Error(reason instanceof Error? reason.message:reason);
} : null
// return一个新的promise
return new MyPromise((resolve, reject) => {
// 把resolveFn重新包装一下,再push进resolve执行队列,这是为了能够获取回调的返回值进行分类讨论
const fulfilledFn = value => {
try {
// 执行第一个(当前的)Promise的成功回调,并获取返回值
let x = resolveFn(value)
// 分类讨论返回值,如果是Promise,那么等待Promise状态变更,否则直接resolve
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (error) {
reject(error)
}
}
// reject同理
const rejectedFn = error => {
try {
let x = rejectFn(error)
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (error) {
reject(error)
}
}
switch (this._status) {
// 当状态为pending时,把then回调push进resolve/reject执行队列,等待执行
case PENDING:
this._resolveQueue.push(fulfilledFn)
this._rejectQueue.push(rejectedFn)
break;
// 当状态已经变为resolve/reject时,直接执行then回调
case FULFILLED:
fulfilledFn(this._value) // this._value是上一个then回调return的值(见完整版代码)
break;
case REJECTED:
rejectedFn(this._value)
break;
}
})
}
catch(rejectFn) {
return this.then(undefined, rejectFn)
}
}
let result = new MyPromise((resolve,reject)=>{
setTimeout(() => {
reject(1000)
}, 1000);
})
result.then(res=>{
console.log('success',res)
}).catch(err=>{
console.log(err,'console.error();')
})