Promise手写源码以及api详解-----学了就会学完就忘系列

一、 Promise 核心逻辑

  1. promise 就是一个类,在执行这个类的时候 需要传递一个执行器(也就是里面这个回调函数,箭头函数),执行器会立即执行( 当我们new Promise 的时候 回调会立即调用)
  2. 回调函数有两个参数resolve,reject,这两个参数其实就是两个函数
  3. Promise 中有三种状态,分别为
    成功 fulfilled
    失败 rejected
    等待 pending
  4. 状态特点:
    等待变成成功 pending ->fulfilled
    等待变成失败 pending ->rejected
    一旦状态确定成功/失败,就不可以改变
  5. resolve 和reject 函数是用来更改状态的
    resolve ->fulfilled
    reject ->rejected
  6. 我们创建完promise 对象以后,我们可以创建一个变量去接收
    promise 下面可以调用then方法来传递两个回调函数,成功与失败,也就说当我们调用then 在这里插入代码片方法的时候我们要去判断promise的返回状态,如果成功则调用的第一个(成功的回调函数),失败则第二个(失败的回调函数)
  7. then 方法内部做的事情就是判断状态,如果成功则调用的第一个(成功的回调函数),失败则第二个(失败的回调函数), then 成功回调(successCallback)有一个参数,表示成功之后返回的值valuethen失败回调(failCallback)后有一个返回值reason失败原因

二、 Promise 基础代码

  1. 通过class关键字创建一个类 MyPromise
  2. 我们需要使用构造函数constructor 来接受这个构造函数,executor代表执行器(执行器是立即执行的,执行器就代表回调函数)
/*
    1、通过`class`关键字创建一个类 MyPromise
    2、我们需要使用构造函数constructor 来接受这个构造函数,executor代表执行器(执行器是立即执行的,执行器就代表回调函数)
*/
const PENGDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
    constructor(executor) {
        // 当前我们是在一个类里面,我们要通过this去访问
        executor(this.resolve, this.reject)

    }
    /*
       1、 为什么定义成箭头函数?
        将来在调用resolve 和reject的时候是直接调用的,如果是普通函数,函数里面的指向-window/reject,如果是箭头函数,会改变this指向,是内部指向类的实例对象,指向promise 对象
        2、 resolve 和reject 就是用来更改状态的。
        3、我们要求定义状态,定义成常量,好处:复用,便于开发。
      
    */
    // 初始状态PENGDING

    status = PENGDING
    /*
        8、设置默认成功之后的值,失败之后的原因
    */
    value = undefined
    reason = undefined
    /*
        9、成功回调,失败回调诉默认值
    */
    successCallback = undefined
    failCallback = undefined
    resolve = value => {
        /*
            4、如果状态不是等待,阻止程序向下执行,否则将状态更改为成功
        */
        if (this.status !== PENGDING) return;
        this.status = FULFILLED
        /*
           7、保存成功之后的值 ,then方法中调用失败回调(successCallback)的时候可以传递当前保存的this.value
        */
        this.value = value
        /*
            10、判断成功回调是否存在,如果存在则调用,
        */
        this.successCallback && this.successCallback(this.value)
    }
    reject = reason => {
        /*
            5、如果状态不是等待,阻止程序向下执行,否则将状态更改为失败
        */
        if (this.status !== PENGDING) return;
        this.status = REJECTED
        /*
          7、保存失败之后的原因,then方法中调用失败回调(failCallback)的时候可以传递当前保存的this.reason
       */
        this.reason = reason
        /*
           10、判断失败回调是否存在,如果存在则调用,
       */
        this.failCallback && this.failCallback(this.reason)
    }
    // 6、then方法 判断状态
    then(successCallback, failCallback) {
        if (this.status === FULFILLED) {
            successCallback(this.value)
        } else if (this.status === REJECTED) {
            failCallback(this.reason)
        } else {
            // 9、这里我们处理的就是当我们处于pending 状态的时候也就是出现异步情况的时候的.首先我们把成功回调和失败回调存储起来,等异步代码执行完毕之后才执行这个成功/失败回调 -然后我们就要找成功resolve-失败reject的回调
            this.successCallback = successCallback
            this.failCallback = failCallback
        }
    }
}


//调用
let promise = new MyPromise((resolve, reject) => {
  resolve('成功')
    // reject('失败')
})

promise.then(value => {
    console.log(value)
 }, reason => { 
     console.log(reason)
 })

三、当Promise 类中加入异步逻辑

  • 假设我们调用的时候是下面这种,出现异步的情况 延时返回-
let promise = new MyPromise((resolve, reject) => {
    // 假设当出现异步情况
    setTimeout(()=>{
        resolve('成功')
    },2000)
    // reject('失败')
})

promise.then(value => {
    console.log(value)
 }, reason => { 
     console.log(reason)
 })

1、 出现异步情况的实现办法

1 当出现`setTimeOut` 或者其他异步的情况的时候,导致代码没有直接调用`resolve`/`reject` 函数,此时 状态是`pengding` 所以按照代码运行顺序会直接进入到`then`方法,`then`方法会先执行,但是此时因为状态一直是`pengding` 我们并不知道是调用`successCallBack` 还是failCallBack,

2 ------------所以我们先将其存储(代码注释①)起来,当异步代码执行完毕之后我们才会执行resolve/reject,然后去判断成功/失败回调是否存在,若存在则调用它(代码注释②)。

const PENGDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }
    status = PENGDING
    value = undefined
    reason = undefined    
    successCallback = undefined
    failCallback = undefined
    resolve = value => {
        if (this.status !== PENGDING) return;
        this.status = FULFILLED
        this.value = value
           /*  注释② */ 
        this.successCallback && this.successCallback(this.value)
    }
    reject = reason => {
        if (this.status !== PENGDING) return;
        this.status = REJECTED
        this.reason = reason
          /*  注释 ② */ 
        this.failCallback && this.failCallback(this.reason)
    }
    then(successCallback, failCallback) {
        if (this.status === FULFILLED) {
            successCallback(this.value)
        } else if (this.status === REJECTED) {
            failCallback(this.reason)
        } else {
            /*  注释①
            - 这里处理的就是当处于pending ,也就是出现异步情况的时候的:
            - 首先我们把成功回调和失败回调存储起来,
            - 等异步代码执行完毕之后才执行这个成功/失败回调 
            - 然后我们就要找成功resolve-失败reject的回调
            */ 
            this.successCallback = successCallback
            this.failCallback = failCallback
        }
    }
}

四、实现 then 方法多次调用添加多个处理函数

then 方法被多次调用的时候,每一个then 方法中传递的回调函数都是要被执行的,这个时候我们要如何处理呢?

  • 假设我们调用的时候是下面这种,多次调用then 方法,
		
		let promise = new MyPromise((resolve, reject) => {
		    // 假设当出现异步情况
		    setTimeout(()=>{
		        resolve('成功')
		    },2000)
		    // reject('失败')
		})
		
		promise.then(value => {
		    console.log(value)
		 }, reason => { 
		     console.log(reason)
		 })
		 
		promise.then(value => {
		    console.log(value)
		 }, reason => { 
		     console.log(reason)
		 })
		 
		promise.then(value => {
		    console.log(value)
		 }, reason => { 
		     console.log(reason)
		 })

1、实现过程及分析

两种情况,一种是同步的情况 ,一种是异步的情况
下面我们就详细说明:每一个then 方法的回调函数都应该存储起来,当状态变为成功或者失败的时候,在依次调用里面的回调函数 上一个实例中出现异步的情况我们每次只能存储一个回调函数,所以我们要基于上面的情况再次进行处理

  1. 找到成功与失败回调设置默认值 由undefined 改为[]空数组,便于我们去存储多个回调函数
  2. 我们找到存储回调的地方将赋值改成 将我们的每个回调 push到我们的相应存储数组里面
  3. 当这个状态是成功还是失败的时候,这个时候我们应该去调用数组中的函数,这个函数如何调用呢?
    循环数组(while) 并调用
const PENGDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }
    status = PENGDING
    value = undefined
    reason = undefined
    // successCallback = undefined
    // failCallback = undefined
    successCallback = []
    failCallback = []
    resolve = value => {
        if (this.status !== PENGDING) return;
        this.status = FULFILLED
        this.value = value
        // this.successCallback && this.successCallback(this.value)
        // shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
        while(this.successCallback.length>0) this.successCallback.shift()(this.value)
    }
    reject = reason => {
        if (this.status !== PENGDING) return;
        this.status = REJECTED
        this.reason = reason
        // this.failCallback && this.failCallback(this.reason)
        // shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
        while(this.failCallback.length>0) 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 = successCallback
            // this.failCallback = failCallback
            this.successCallback.push(successCallback)
            this.failCallback.push(failCallback)
        }
    }
}

打印结果

Promise手写源码以及api详解-----学了就会学完就忘系列_第1张图片

五、实现 then 方法的链式调用(一)-普通值

Promisethen 方法是可以链式调用的,后面then方法的回调函数拿到的值实质上是上一个then方法的回调函数的返回值
下面我们来演示一下链式调用返回的普通值的时候:

let promise = new MyPromise((resolve, reject) => {
    // 当出现异步情况
    // setTimeout(()=>{
    //     resolve('成功')
    // },2000)
    resolve('成功')
    // reject('失败')
})

promise.then(value => {
    console.log(value)
    return 100;
}).then(value => {
    console.log(value)  //100
})

1、 实现方法及分析

下面我们通过两个步骤来实现

  • 如何实现then方法的链式调用
    先我们要清楚,then 方法是Promise 下面的,如果我们想要实现then方法下面的链式调用,那我们的每一个then 方法返回的都应该是一个Promise对象,这样才可以链式调用then
  • 如何把上一个函数的返回值,传递给下一个then 方法的回调函数
    首先拿到回调返回值,然后 把这个返回值传递给下一个then回调函数,实际上下一个then 就是我们返回这个promise2下面的then, 那也就是说我们调用promise里面的resolve方法就好了,当我们调用完resolve 之后,就实现了
	const PENGDING = 'pending'
	const FULFILLED = 'fulfilled'
	const REJECTED = 'rejected'
	class MyPromise {
	    constructor(executor) {executor(this.resolve, this.reject)}
	    status = PENGDING
	    value = undefined
	    reason = undefined
	    successCallback = []
	    failCallback = []
	    resolve = value => {
	        if (this.status !== PENGDING) return;
	        this.status = FULFILLED
	        this.value = value
	        while(this.successCallback.length>0) 
	        this.successCallback.shift()(this.value)
	    }
	    reject = reason => {
	        if (this.status !== PENGDING) return;
	        this.status = REJECTED
	        this.reason = reason
	        while(this.failCallback.length>0) 
	        this.failCallback.shift()(this.reason) 
	    }
	    then(successCallback, failCallback) {
	        /* 
	         1. 既然我们要返回一个Promise 对象,那么我们创建一个Promise 对象,
	         2. 然后我们通过return 关键字 返回 promise2
	         3. 传递一个执行器,(立即执行)使原来的代码保持原有的功能
	         4. ---这样我们就实现了步骤一
	       */
	        let promise2 = new MyPromise((resolve,reject)=>{ 
	            if (this.status === FULFILLED) {
	              /* 实现步骤二
	               ①. 首先拿到函数的返回值(成功/失败)返回的promise2
				   ②. 把返回值传递给下一个then回调函数,调用promise2里的resolve方法
		         */
	              let x=  successCallback(this.value)
	              resolve(x)
	            } else if (this.status === REJECTED) {
	              failCallback(this.reason)
	               
	            } else {
	                this.successCallback.push(successCallback)
	                this.failCallback.push(failCallback)
	            }
	        });
	        return promise2
	    }
	}

- 返回实现结果
在这里插入图片描述

六、实现 then 方法的链式调用(一)-Promise对象

当我们以promise对象为返回值时

let promise = new MyPromise((resolve, reject) => {
    resolve('成功')
    // reject('失败')
})
// 先定义一个promise 对象
function otherPromise(params) {
    return new Promise((resolve,reject)=>{
        resolve('other')
    })
}
// 
promise.then(value => {
    console.log(value)
    return otherPromise();
}).then(value => {
    console.log(value)
})

1、当返回值是promise对象时实现方法

接下来我们要去判断 x 是普通值还是promise 对象
如果是普通值,直接resolve
如果是promise对象 查看promise对象返回的结果
在根据promise对象返回的结果(Promise 对象的状态),
若成功-----> 调用resolve 将成功的值传递给下一个
若失败-----> 调用reject 将失败的结果传递给下一个


const PENGDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }
    status = PENGDING
    value = undefined
    reason = undefined
    successCallback = []
    failCallback = []
    resolve = value => {
        if (this.status !== PENGDING) return;
        this.status = FULFILLED
        this.value = value
        while (this.successCallback.length > 0) 
        this.successCallback.shift()(this.value)
    }
    reject = reason => {
        if (this.status !== PENGDING) return;
        this.status = REJECTED
        this.reason = reason
        while (this.failCallback.length > 0) 
        this.failCallback.shift()(this.reason)

    }
    then(successCallback, failCallback) {

        let promise2 = new MyPromise((resolve, reject) => {

            if (this.status === FULFILLED) {
                let x = successCallback(this.value)
                resolvePromise(x, resolve, reject)
                //   resolve(x)
            } else if (this.status === REJECTED) {
              failCallback(this.reason)
            } else {
                this.successCallback.push(successCallback)
                this.failCallback.push(failCallback)
            }
        });

        // 2然后我们通过return 关键字 返回promise2
        return promise2
    }
}

 // 判断x是普通值还是Promise对象
function resolvePromise(x, resolve, reject) {
    //  我们只需要判断x 是不是MyPromise 的这个实例
    if (x instanceof MyPromise) {
        // x.then(value => { resolve(value)}, reason => { reject(reason)})
        //简化代码
        x.then(resolve,reject)
    } else {
        resolve(x)
    }
}

七、then 方法链式调用识别 Promise 对象自返回

  • 在then 方法中是可以返回promise 对象的,但是有一种个例情况

      在then方法中 不能返回当前这个方法他所返回的这个promise 对象,
      如果说你所返回的then方法返回的那个promise对象,
      那这个时候就发生了promise对象的循环调用,程序是不允许的,会报错!!
    

1、html模拟演示个例

我们新建一个index.html文件,输入以下代码,
模拟演示一下

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var a = new Promise(function (resolve, reject) {
            resolve('100')
        })
        var p1 = a.then(function (value) {
            console.log(value)
            return  p1
        })
    </script>
</body>

</html>

查看当前系统结果 会报错
在这里插入图片描述

2、在当前promise中判断个例情况

首先我们调用的时候

let promise = new MyPromise((resolve, reject) => {
    resolve('成功')
    // reject('失败')
})
let p1=promise.then(value => {
    console.log(value)
    return p1;
})
p1.then(value => {
    console.log(value)
},reason=>{
    console.log(reason.message)
})

3、Promise 对象自返回解决方法

   1、 找到then方法
   2、返回的promise对象就是promise2 ,
   	  成功的回调返回的promise对象就是x
   3、我们只需要判断promise对象和x是否相等,
      如果相等则就说明是自己返回了自己,
      出现问题了,我们就要执行reject,
   4、在resolvePromise中处理
const PENGDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
    constructor(executor) { executor(this.resolve, this.reject)}
    status = PENGDING
    value = undefined
    reason = undefined
    successCallback = []
    failCallback = []
    resolve = value => {
        if (this.status !== PENGDING) return;
        this.status = FULFILLED
        this.value = value
        while (this.successCallback.length > 0) this.successCallback.shift()(this.value)
    }
    reject = reason => {
        if (this.status !== PENGDING) return;
        this.status = REJECTED
        this.reason = reason

        while (this.failCallback.length > 0) this.failCallback.shift()(this.reason)

    }
    then(successCallback, failCallback) {

        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                // 异步代码原因:是此过程执行完在执行词代码 是promise2 可以传值不会报错
                setTimeout(()=>{
                    let x = successCallback(this.value)
                    resolvePromise(promise2,x, resolve, reject)
                },0)
            } else if (this.status === REJECTED) {
              failCallback(this.reason)
            } else {
                this.successCallback.push(successCallback)
                this.failCallback.push(failCallback)
            }
        });
        return promise2
    }
}


function resolvePromise(promise2,x, resolve, reject) {
    // 如果相等,就说明自己反悔了自己,捕捉到了问题,提示错误
  if(promise2===x){
    //   使用return 是出现问题程序报错后阻止代码向下执行
     return reject(new TypeError('Chaining cycle detected for promise #'))
  }
    if (x instanceof MyPromise) {
       
        x.then(resolve,reject)
    } else {
        resolve(x)
    }
}

执行结果:
我们就可以直接查看我们捕捉的错误,就可以啦~
在这里插入图片描述

八、捕获错误及then链式调用其他状态代码

上述的所有我们没有对任何错误情况进行捕捉,下面我们对一些错误进行捕捉

1、 执行器错误

	当执行器中的代码在执行的过程当中发生错误的时候,
	我们就要把执行的状态变成是失败的状态
let promise = new MyPromise((resolve, reject) => {
    // 我们抛出错误演示一下
    throw new Error('执行器错误')
    resolve('成功')
    // reject('失败')
})
promise.then(value => {
    console.log(value)
},reason=>{
    console.log(reason,‘=)
})
	捕捉异常处理,我们只需要在上述代码中在执行器处 
	通过try ,catch来捕获异常,调用reject方法打印错误
 constructor(executor) {
        // 执行器中捕捉错误
        try{
            executor(this.resolve, this.reject)
        } catch (e){
            // 如果捕捉到了错误 我们把错误原因e传递过去
            this.reject(e)
        }
        // executor(this.resolve, this.reject)
    }

结果显示
Promise手写源码以及api详解-----学了就会学完就忘系列_第2张图片

2、 then方法里面的回调函数错误

then方法里面的回调函数,若在执行过程中报错了,
下面我们演示一下回调函数执行中异常并抛出错误。
let promise = new MyPromise((resolve, reject) => {
    resolve('成功')
    // reject('失败')
})
promise.then(value => {
    console.log(value)
       // 我们抛出错误演示一下
    throw new Error('回调函数错误')
},reason=>{
    console.log(reason)
}).then(value => {
    console.log(value)
},reason=>{
    console.log(reason.message)
})

捕捉到这个错误,并且这个错误要在下一个then方法的错误回调reject中捕捉到,并返回
then(successCallback, failCallback) {
        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                setTimeout(()=>{
                    // then方法里面的回调函数中捕捉错误
                    try{
                        let x = successCallback(this.value)
                        resolvePromise(promise2,x, resolve, reject)
                    }catch(e){
                        reject(e)
                    }
                },0)
            } else if (this.status === REJECTED) {
              failCallback(this.reason)
            } else {
                this.successCallback.push(successCallback)
                this.failCallback.push(failCallback)
            }
        });
        return promise2
    }

实现结果
在这里插入图片描述

3、链式调用捕捉错误结果返回

我们之前处理链式调用 只处理了成功的状态 并没有处理失败的状态,
那么当失败的时候或者当代码是异步的时候都没有处理

模拟演示实现错误调用

let promise = new MyPromise((resolve, reject) => {
    // resolve('成功')
    reject('失败')
})
promise.then(value => {
    // console.log(value)
},reason=>{
    console.log(reason)
    return "失败"
}).then(value => {
    console.log(value,'捕捉错误回调')
})

捕捉代码处理,在then方法中

   then(successCallback, failCallback) {
        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                setTimeout(()=>{
                    // then方法里面的回调函数中捕捉错误
                    try{
                        let x = successCallback(this.value)
                        resolvePromise(promise2,x, resolve, reject)
                    }catch(e){
                        reject(e)
                    }
                },0)
            } else if (this.status === REJECTED) {
              // then方法里面的失败函数中捕捉错误
              setTimeout(()=>{
                try{
                    let x = failCallback(this.reason)
                    resolvePromise(promise2,x, resolve, reject)
                }catch(e){
                    reject(e)
                }
            },0)
            } else {
                this.successCallback.push(successCallback)
                this.failCallback.push(failCallback)
            }
        });
        return promise2
    }

执行结果
在这里插入图片描述

4、当代码是异步的情况捕捉错误

  • 当我们异步调用的时候

let promise = new MyPromise((resolve, reject) => {
    setTimeout(()=>{
        resolve('成功....')
    },2000)
    // resolve('成功')
    // reject('失败')
})
promise.then(value => {
    console.log(value)
    return 'aaaa'
},reason=>{
    console.log(reason)
}).then(value => {
    console.log(value,'捕捉错误回调')
})
  • 捕捉处理

     之前我们链式调用的时候是push到一个数组里,
     那这里呢我们需要push一个函数进去,
     在这个函数里面进行函数回调 成功/失败
    
const PENGDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
    constructor(executor) {
        try{
            executor(this.resolve, this.reject)
        } catch (e){
            this.reject(e)
        }
    }
    status = PENGDING
    value = undefined
    reason = undefined
    successCallback = []
    failCallback = []
    resolve = value => {
        if (this.status !== PENGDING) return;
        this.status = FULFILLED
        this.value = value
        // 当处理异步 捕捉错误的时候这个手已经不需要传值了,
        while (this.successCallback.length > 0) this.successCallback.shift()()
    }
    reject = reason => {
        if (this.status !== PENGDING) return;
        this.status = REJECTED
        this.reason = reason
 // 当处理异步 捕捉错误的时候这个手已经不需要传值了,
        while (this.failCallback.length > 0) this.failCallback.shift()()
    }
    then(successCallback, failCallback) {
        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                setTimeout(()=>{
                    // then方法里面的回调函数中捕捉错误
                    try{
                        let x = successCallback(this.value)
                        resolvePromise(promise2,x, resolve, reject)
                    }catch(e){
                        reject(e)
                    }
                },0)
            } else if (this.status === REJECTED) {
            //   failCallback(this.reason)
              setTimeout(()=>{
                // then方法里面的回调函数中捕捉错误
                try{
                    let x = failCallback(this.reason)
                    resolvePromise(promise2,x, resolve, reject)
                }catch(e){
                    reject(e)
                }
            },0)
            } else {
                this.successCallback.push(()=>{
                    setTimeout(()=>{
                        // then方法里面的回调函数中捕捉错误
                        try{
                            let x = successCallback(this.value)
                            resolvePromise(promise2,x, resolve, reject)
                        }catch(e){
                            reject(e)
                        }
                    },0)
                })
                this.failCallback.push(()=>{
                    setTimeout(()=>{
                        // then方法里面的回调函数中捕捉错误
                        try{
                            let x = failCallback(this.reason)
                            resolvePromise(promise2,x, resolve, reject)
                        }catch(e){
                            reject(e)
                        }
                    },0)
                })
            
            }
        });
        return promise2
    }
}

实现结果 2s后打印
在这里插入图片描述


九、链式调用时将then方法的参数变成可选参数

处理方法

// 在then 方法中添加
   successCallback = successCallback ? successCallback : value => value;
   failCallback = failCallback ? failCallback : reason => { throw reason }

//成功调用

let promise = new MyPromise((resolve, reject) => {
        resolve('成功....')
})
promise.then().then().then(value=>console.log(value)) 

// 失败调用

let promise = new MyPromise((resolve, reject) => {
    reject('失败')
})
promise.then().then().then(value=>console.log(value),reason=>{console.log(reason)})

十、Promise.all 方法详解

  1. 主要是解决异步并发问题的,
  2. 允许我们按照异步代码调用的顺序,得到异步代码执行的结果
  3. 接受一个数组作为参数,返回值是一个promise对象
  4. 在数组中填入任何值 ,参数值值的顺序是返回值结果的顺序
  5. 可以链式调用then方法
  6. 在all方法参入中所有的promise对象,
    如果状态都是成功的那么all方法最后的结果就是成功的;
    如果有一个是失败的那么最后的结果就是失败的的;
  7. 静态方法 static all
function p1(){
    return new MyPromise(function(resolve,reject){
        setTimeout(function(){
            resolve('p1')
        },2000)
    })
}
function p2(){
    return new MyPromise(function(resolve,reject){
            resolve('p2')
    })
}

上述代码中如果我们先调用p1(),后调用p2(),按照正常代码执行顺序我们肯定先得到的是p2()后得到的是p1()(p1中有延时定时器),

如果我们放置于Promise.all 中

Promise.all(['a','b',p1(),p2(),'c']).then(function(result){
            // return ->['a','b','p1','p2','c']
        })

我们就会是先得到 p1() 然后是p2()

那么下面我们依然按照之前的Promise基础上继续去开发all方法

1、Promise.all() 的使用

 1、参数是一个数组 arr  
 2、我们就要去循环这个数组进行循环处理,在循环的过程中,我们要判断是普通值还是promise对象
 3、如果是普通值,直接放到结果数组中,
    如果是promise 对象,就先去执行这个promise对象,再把promsie的结果放到结果数组中
    如果状态是成功的那么再把promsie的结果放到结果数组中
    如果状态都是成功的all方法最后的结果就是成功的;
	如果有一个是失败的那么最后的结果就是失败的的;
 4、那么就需要我们先声明一个结果数组result 
 5、然后我们定义一个变量index 初始为0   
    去判断当前参数中异步的代码是否都执行完毕,
    我们在每次把参数执行结果放入结果数组中时 index++,
    当index === 参数数组长度 的时候 就代表 所有参数都执行完毕,
    这个之后我们执行resolve(),
    static all(arr){
        let result=[]
        let index=0
        return new Promise((resolve,reject)=>{
            function addData(key,value) {
                result[key]=value
                index++
                if(index===arr.length){
                    resolve(result)
                }
            }
            for(let i=0;i<arr.length;i++){
                let current=arr[i];
                if(current instanceof MyPromise){
                    current.then(value=>addData(i,value),reason=>reject(reason))
                }else{
                    addData(i,arr[i])
                }
            }
        })
    }

使用Promise.all() 执行


MyPromise.all(['a','b',p1(),p2(),'c']).then(result=>console.log(result))

//[ 'a', 'b', 'p1', 'p2', 'c' ]

十一、Promise.resolve() 方法详解

  1. Promise.resolve()方法是将给定的值,转化成promise对象,也就是说 Promise.reasolve()方法的返回值就是一个Promise对象
  2. Promise.resolve()方法 也可以接受一个promise对象,在Promise,resolve()方法内部会判断,给定的值是普通值还是promise对象,如果是promise对象会原封不动的作为该方法的返回值,所以才能链式调用通过then方法的成功回调拿到返回值,如果是普通值则创建一个promise对象,把给定的值包裹在Promise对象当中,然后再去调用
  3. Promise.resolve() 静态方法 static resolve

1、Promise.resolve() 的使用

 static resolve(value){
        if(value instanceof MyPromise){
            return value

        }else{
        return   new Promise(resolve=>resolve(value))
        }
    }

然后我们来验证一下


function p1(){
    return new MyPromise(function(resolve,reject){
        setTimeout(function(){
            resolve('p1')
        },2000)
    })
}
MyPromise.resolve(100).then(value=>console.log(value))
 //100
MyPromise.resolve(p1()).then(value=>console.log(value)) 
//p1 2s后打印

十二、finally 方法详解

finally 方法不是一个静态方法,要定义在类的原型对象上

  1. 无论当前的Promise对象最终的状态是成功/失败,finally这个方法都会被执行一次
    2. 在finally方法可以链式调用then方法来拿到当前promise对象最终返回的结果
    使用案例
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        function p1() {
            return new Promise(function (resolve, reject) {
                resolve('finally')
            })
        }
        p1().finally(() => {
            console.log('finally')
        }).then(value => console.log(value))
    </script>
</body>

</html>

1、finally 的使用

finally(callback){
      return  this.then(value=>{
            callback()
            // 若成功则传递给下一个then返回值value
            return value
        },reason=>{
            callback()
            // 若失败则通过throw传递给下一个then 失败理由 reason
            throw reason
        })
    }

调用案例

function p2(){
    return new MyPromise(function(resolve,reject){
        reject('p2 reject')
    })
}
p2().finally(() => {
    console.log('finally')
}).then(value => console.log(value),reason=>console.log(reason))
// finally
//p2 reject

如果我们在调用的时候return的 是一个异步执行的promise对象,那我们调用时。如下代码调用,

function p1(){
    return new MyPromise(function(resolve,reject){
        setTimeout(function(){
            resolve('p1')
        },2000)
    })
}
function p2(){
    return new MyPromise(function(resolve,reject){
       resolve('p2 resolve')
    })
}
p2().finally(() => {
    console.log('finally')
    //异步
    return p1()
}).then(
		value => console.log(value),
		reason=>console.log(reason)
	)
//这个时候控制台输出为 立即 finally   p2 resolve, 并没有两秒的延迟,

上述调用中我们想要实现的是延迟两秒输出,但是因为本身自带的功能导致没有延迟,失去我们想要的效果,所以我们在promise代码中借助resolve方法,

  1. 查看callback方法的返回值
  2. 若普通值:则转化为promise对象,然后等待等待primise对象的执行完成,然后返回结果
  3. promise对象我们就等你执行完成,然后再返回value
finally(callback){
      return  this.then(value=>{
            // callback()
         return   MyPromise.resolve(callback()).then(()=>value)
            // 若成功则传递给下一个then返回值value
            // return value
        },reason=>{
            return MyPromise.resolve(callback()).then(()=>{throw reason})
            callback()
            // 若失败则通过throw传递给下一个then 失败理由 reason
            throw reason
        })
    }
//finally   两秒后 p2 resolve

十三、catch 方法详解

catch 方法的作用是用来处理当前这个promise对象最终的状态为失败的情况的,也就是说我们是可以不传递失败回调的,这时候这个失败回调就会被catch方法所捕获,从而就会传入到catch方法中的回调函数,

  • 我们首先来下一个demo 来演示一下catch方法的使用
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        function p1() {
            return new Promise(function (resolve, reject) {
                resolve('catch')
            })
        }
        p1()
            .then(value=>console.log(value))
            .catch(reason=>console.log(reason))

    </script>
</body>
</html>

下面我们在promise 源码上加上这个方法,来捕获失败回调函数

1、catch 使用

  • 在catch 方法中调用then方法,在成功的地方传入undefined 在失败的地方传入一个回调函数。
  catch(failCallback){
      return  this.then(undefined,failCallback)
    }

我们来调用一下

function p2(){
    return new MyPromise(function(resolve,reject){
        reject('p2 reject')
        // resolve('p2 resolve')
    })
}
p2().then().catch(reason=>console.log(reason))
// p2 reject

总结:promise 源码整理



const PENGDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }
    }
    status = PENGDING
    value = undefined
    reason = undefined
    successCallback = []
    failCallback = []
    resolve = value => {
        if (this.status !== PENGDING) return;
        this.status = FULFILLED
        this.value = value
        while (this.successCallback.length > 0) this.successCallback.shift()()
    }
    reject = reason => {
        if (this.status !== PENGDING) return;
        this.status = REJECTED
        this.reason = reason
        while (this.failCallback.length > 0) this.failCallback.shift()()
    }
    then(successCallback, failCallback) {
        successCallback = successCallback ? successCallback : value => value;
        failCallback = failCallback ? failCallback : reason => { throw reason }
        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                        let x = successCallback(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) {
                //   failCallback(this.reason)
                setTimeout(() => {
                    try {
                        let x = failCallback(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else {
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = successCallback(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = failCallback(this.reason)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })

            }
        });
        return promise2
    }
    finally(callback){
      return  this.then(value=>{
            // callback()
         return   MyPromise.resolve(callback()).then(()=>value)
            // return value
        },reason=>{
            return MyPromise.resolve(callback()).then(()=>{throw reason})
            callback()
            throw reason
        })
    }
    catch(failCallback){
      return  this.then(undefined,failCallback)
    }
    static all(arr){
        let result=[]
        let index=0
        return new Promise((resolve,reject)=>{
            function addData(key,value) {
                result[key]=value
                index++
                if(index===arr.length){
                    resolve(result)
                }
            }
            for(let i=0;i<arr.length;i++){
                let current=arr[i];
                if(current instanceof MyPromise){
                    current.then(value=>addData(i,value),reason=>reject(reason))
                }else{
                    addData(i,arr[i])
                }
            }
        })
    }
    static resolve(value){
        if(value instanceof MyPromise){
            return value
        }else{
        return   new Promise(resolve=>resolve(value))
        }
    }
}
function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #'))
    }
    if (x instanceof MyPromise) {
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}


以上内容均为个人学习笔记,不存在任何其他或者商业行为 ,如有侵权或者其他,必删除。请私聊或者评论告知。

你可能感兴趣的:(【JavaScript,专栏】,【杜杜的学习笔记】,javascript,前端)