promise,promise-all原理-自我记录

241 阅读4分钟

let status = { //promise默认有三种状态

pending: 'pending', //进行中

fulfilled: 'fulfilled', //成功

rejected: 'rejected' //失败

}

function resolvePromise(promise2, x, resolve, reject) {} //这个是为了考虑的全面点,如果then返回了new promise

class promise { //new的时候会传参,这个参数会默认给到constructor中

constructor(excutor) {

this.status = 'pending' //给到一个默认状态

this.value = '' //成功的时候将传递的值赋值到上面

this.reason = '' //失败的时候将传递的值赋值到上面

this.onResolveCallBacks = [] //在then中收集成功的回调函数,因为then中状态还是pending不会调用这个回调

this.onRejectedCallBacks = [] //在then中收集失败的后的处理,因为then中状态还是pending不会调用这个回调

const resolve = (value) => { //一般我们在调用resolve的时候都会传出去一个值

if (this.status = status.pending) { //如果调用了resolve,判断下当前是否进行中,

//进行中的话将状态改成完成态

this.status = status.fulfilled //完成态

this.value = value //之所以保存这个是为了调用then方法的时候将这个传递进去

this.onResolveCallBacks.forEach(item => item()) //如果这个数组不为空说明这个方法是异步的,需要等到回调的值有值了再去执行所以代码在this.value后面

}

}

const reject = (value) => {

if (this.status = status.pending) { //不管调用reject还是resolve都需要是进行中的状态

this.status = status.rejected //调用失败函数更改状态值

this.reason = value //保存下,如果调用catch的话将失败的值返回出去

this.onRejectedCallBacks.forEach(item => item())

}

}

executor(resolve, reject) //这个是executor是用户写的时候传递的参数,我们调用它,将定义的resolve,和reject传进去

//一般new promise的时候 new promise((resolve,reject,) => { 这里可以做自己的一些处理程序})

}

then(onFulfilled, onRejected) { //then方法,一般是回调的时候使用,里面的额参数类比我们接口使用时response => {}传入的这个函数

//因为每次调用then方法都会产生一个新的promise,所以这个内部还需要去new promise

let promise2 = new promise((resolve, rejected) => {

if (this.status === status.fulfilled) { //成功的话

try {

let x = onFulfilled(this.value) //那就是执行用户传入的那个函数然后把之前resovle出来的this.value传入,如果有返回值的话那么我们需要取出来,作为下一次继续then的参数值

resolve(x) //这样执行的话我们又把x赋值到this.value上了,下一次onFulfilled可以把上一次的值传入

} catch (e) {

reject(e)

}

}

if (this.status === status.rejected) { //失败的话

try {

let x = onRejected(this.reason) //执行传入的函数传入失败的值

resolve(x) //如果是执行的错误方法,那就把它sesolve放到value上作为下一次的参数值

} catch (e) {

rejected(e)

}

}

if (this.status === status.pending) { //如果执行then方法的时候还是pending状态(异步的先在还不能执行 onFulfilled,拿不到上一步的回调)那就将当前then后

//的回调存起来,所以我们在类中还需要申明两个数组

this.onResolveCallBacks.push(() => {

try {

let x = onFulfilled(this.value) //将成功后的处理塞入数组相当于订阅

resolve(x) //将这个值存入value作为下一次then的值

} catch (e) {

reject(e)

}

})

this.onRejectedCallBacks.push(

() => {

try {

let x = onFulfilled(this.reason) //将失败后的处理塞入数组相当于订阅

resolve(x) //将这个值存入value作为下一次then的值

} catch (e) {

reject(e)

}

}

)

}

})

return promise2

}

all(promises) { //all方法是一个静态方法,因为promise.all(){}.then 可以then所以内部是一个new promise

return new promise((resolve, reject) => {

let arrValue = [] //什么一个数组去储存所有的返回值

let index = 0

function keepProcess(i, value) {

arrValue[i] = value

if (++index === promises.length) { //当标识的数字跟promise的长度一样说明执行完毕了把结构resolve出去

resolve(arrValue)

}

}

//这个时候需要判断下传入的数组是不是promise,循环数组因为我们需要并发所以我们使用for循环

for (let i = 0; i < promises.length; i++) {

if (typeof promises[i] === 'function') { //判断当前是否是promise还是普通值

promises[i].then(res => { //如果是promise还需要执行把结果传过去

keepProcess(i, res)

})

} else {

keepProcess(i, promises[i])

}

}

})

}

race(promises) { //race的意思是赛跑哪个跑得快就用谁的,传入多个promises,哪个先执行完使用谁的,其他的也会执行只是不会采用结果

new promise((resolve, reject) => { //内部还是包装成一个promise,因为下面要使用它的resolve,依靠resolve去获取第一个执行完的值

for (let i = 0; i < promises.length; i++) {

if (typeof promises[i] === 'function') {

promises[i].then(resolve) //之前一直没理解,看了下then方法,这个resolve会作为onFulfilled去执行,resolve中会改变pend状态,那么外部的new promise就会把这个值产出,使用then时候就可以获取到

} else {

resolve(promises[i]) //如果是普通类型也直接产出

}

}

})

}

}

let p = new Promise((resolve, reject) => { //利用race,实现立即中断promise为失败状态

setTimeout(() => { //这里申明一个promise

resolve('成功');

}, 3000);

})

function wrap(p){ //一个wrap函数

let abort;

let p1 = new Promise((resolve,reject)=>{ //再申明一个promise,将reject方法保存到一个变量上

abort = reject;

});

let newPromise = Promise.race([p1,p]) //传入之前的两个promise,在race中

newPromise.abort = abort //rece里面存储一个reject方法

return newPromise

}

let p1 = wrap(p); //这个拿到的p1就是promise.race,可以在后面.then

p1.then(data => {

console.log('success', data)

}, err => {

console.log('error', err)

})

setTimeout(() => {

p1.abort('超过2s了');

}, 2000);

//总结就是p这个promise设置了个延时器3s,p1promise只是保存了reject,没有resolve或者reject,那么我们在外部可以设置个定时器2s模拟下,2s就调用reject这样程序就停止了

Promise.prototype.finally = function (callback) { //finally方法

return this.then((data)=>{

return Promise.resolve(callback()).then(()=>data)

},(err)=>{

return Promise.resolve(callback()).then(()=>{throw err})

})

}

//finally方法是无论如何都会执行,那么它内部本质就是一个then方法,然后取到上一次的结果data传入,还需要考虑后面还需要接着then,那么它内部还会再去promise。resolve()产出保存上一次的结果,然后then就能拿到