Promise从基础到入门

一、Promise前言

(1):函数对象和实例对象

函数对象:将函数作为对象来使用,简称函数对象 (就是直接调用函数原型对象上面的属性或方法)
实例对象:new函数产生一个对象,简称对象!
注意点:?() — ?为函数; ?.call() —?为函数对象!

    function Fn() { //Fn为函数
    }
    let fn = new Fn(); //Fn为构造函数 fn为函数的实例对象(对象)
    console.log(Fn.prototype); // Fn为函数对象
    Fn.call(); //call()都是Fn的实例,定义渣原型上,这边Fn为函数对象
    $('#box');//jq函数
    $.get('.box');//jq函数对象

(2):回调函数

1:同步回调 — 立即执行,完全执行完才结束,不会放入回调队列中
eg:数组遍历相关的回调函数,Promise的excutor函数
2:异步回调 — 不会立即执行,会放入回调队列中
eg:定时器,ajax,promise的成功或失败

  如何判断是同步函数还是异步函数?
  就是在函数后面添加一个输出(log),看看这个输出是先输出还是后输出,先输出的为异步函数,后输出的为同步函数!
    //1:同步回调函数
    let arr = [1, 3, 5];
    arr.forEach(item => { //遍历回调为同步回调函数
      console.log(item);
    })
    console.log('forEach之后');
    //结果 1 3 5 forEach之后  证明这一个函数为同步函数!

    //2:异步函数
    setTimeout(() => { //这个是异步回调,会放入回调队列中稍后执行
      console.log("setTimeout callback");
    })
    console.log("setTimeout 之后");
    //结果: setTimeout 之后 setTimeout callback

(3):错误类型

1:错误类型
Error:所有错误的父类型
ReferenceError:引用变量不存在 (经常遇到)
TypeError:数据类型不正确 (经常遇到)
RangeError:数值不在所在范围内
SyntaxError:语法错误

2:错误处理
捕捉错误:try …catch
抛出错误:throw … error (需要自己再捕获异常 看看出现什么错误)

3:错误对象
message属性:错误相关信息
stack属性:函数调用栈记录

错误类型:

  // 1:ReferenceError:引用变量不存在
     console.log(a); //引用变量错误     Uncaught ReferenceError :a is not defined at

    // 2:TypeError:数据类型不正确
    // let num = null;
    // console.log(num.xxx);
    // let b = {}
    // b.xxx();
    // 类型错误(num为null,而num.xxx需要num为对象才能调用)Uncaught TypeError: Cannot read property 'xxx' of null

    //3: RangeError:数值不在所在范围内
    // function fn() {
    //   fn();
    // }
    // fn();
    //递归函数,回调次数超出了所在范围   Uncaught RangeError: Maximum call stack size exceeded

    //4: SyntaxError:语法错误
    // let abc = """";//语法错误  SyntaxError

捕获异常和抛出异常

    // 因为出现错误后,程序不能继续执行了,需要对错误进行处理,常见的有
    // 1:捕获错误  try ... catch
    // try {
    //   let b;
    //   console.log(b.xxx());
    // } catch (error) {
    //   console.log(error);
    //   console.log(error.message); //Cannot read property 'xxx' of undefined
    //   console.log(error.stack); //TypeError: Cannot read property 'xxx' of undefined
    // }
    // 注意点:try来捕捉错误,catch来显示捕捉的错误! error里面有两个属性,message---提示信息 stack---提示信息和类型错误提示!
    //程序还能继续向下执行!

    // 2:抛出错误
    function something() {
      if (Date.now() % 2 === 1) {
        console.log("当前时间为奇数,执行任务");
      } else { //如果当前时间为偶数抛出异常,有调用者来处理1
        throw new Error('当前时间为偶数,不能执行任务');//抛出异常,需要新建一个Error()---这边是所有错误的父类型1
        //注意点:假如这边直接捕获,就不用try来捕获了
      }
    }
    //来捕获异常
    try {
      something()
    } catch (error) {
      console.log(error.message);
    }

二、Promise基础

(1):Promise是什么?和基本使用

1:Promise是什么

  抽象解析:
    01:Promise是JS中进行异步编程的新的解决方案! (旧的方案是纯回调函数形式 --- 产生回调地狱!)
  具体解析:
    02:从语法上看Promise是一个构造函数! (new Promise ---执行构造函数,返回实例对象)
    03:从功能上看,Promise对象用来封装了一个异步操作最终完成(或失败),及其结果

2:Promise状态

    初始状态为pending ---未确定的
	01:pending变为fulfilled(resolve)  ---满足阶段 ---会回调then()
    02:pending变为rejected(reject)  ---未决定,履行,拒绝阶段  --- 会回调catch()
    Promise的状态只有上述两种状态切换,而且Promise对象只能改变一次
      无论成功还是失败,都会返回一个数据,成功的为value,失败的为reason

3:执行流程

创建和执行流程
第一步:创建一个Promise构造函数,返回一个promise对象,里面传入的是一个执行器函数(同步函数)
第二步:执行器函数里面有两个参数,参数1为成功的回调,参数2为失败的回调,判断成功与失败,里面返回数据(成功的结果或失败的结果或其他值)
第三步:再.then方法中判断里面的是否是函数,若是函数就执行(函数的话,证明是Promise对象,于是可以调用.then方法),否则就忽略。
第四步:再.then方法中,onFulfilled为函数就调用resolve('-成功的数据') 里面的数据,失败也是同理回调,输出数据!


注意点1:resolve函数的作用,就是把promise对象的状态从“未完成”变为成功,(即peding-resolved),在异步操作成功时调用,并且将异步操作结果,作为参数传递到下一个Promise.then方法作为条件。
注意点2:reject函数的作用,就是把promise对象的状态从“未完成”变为失败,(即peding-rejected),在异步操作失败时调用,并且将异步操作结果,作为参数传递到下一个Promise.then方法作为条件。
注意点3:Promise实例生成后,可以使用then方法分别指定resolve状态和rejected状态的回调函数!
注意点4:一个 promise 必须提供一个 then 方法以访问其当前值、终值和据因
promise 的 then 方法接受两个参数,promise.then(onFulfilled, onRejected),这两个都是可选参数

Promise从基础到入门
4:Promise的基本使用

   //1:创建一个Promise对象
    const p = new Promise((resolve, reject) => {
      console.log(0); //执行器函数,为同步函数,优先执行
      //2:异步任务操作
      setTimeout(() => {
        let time = Date.now();
        if (time % 2 === 0) { //偶数成功,奇数失败
          resolve(1) //该Promise成功时,结果值为1,代表包裹这个resolve(1)的Promise的返回的结果为Promise对象和成功值为1
        } else {
          reject(2) //该Promise失败时,结果值为2
        }
      }, 1000)
    })
    p.then(
      value => {
        console.log("onFulfill1()", value); //上面的Promise成功,调用then方法的时,把成功值当做参数传递进来,于是value为1
      },
      reason => {
        console.log("onRejected1()", reason); //上面的Promise失败,调用then方法的时,把成功值当做参数传递进来,于是value为2
      }
    )
    //结果:0 , 还有onRejected1() 2 或onFulfill1() 1

(2):为什么使用Promise

1:指定的回调函数更加灵活:

    旧的:必须在启动异步任务前指定回调函数
    promise:启动异步任务 =>返回promise对象 =>给promise对象绑定回调函数
    而promise是一般是启动异步任务之后,才指定回调函数!也可以等有了结果,在指定!

2:promise支持链式调用的,可以解决回调地狱!

    什么是回调地狱?回调函数嵌套调用(一个异步操作嵌套一个异步操作。。。),外部嵌套函数异步的执行结果为内层的嵌套函数的执行条件
    回调地狱的缺点? 阅读性差,不便于处理异常
    解决方案1:Promise链式调用;
    但是async/await更为简洁,是最好的方式!
    
    注意点:
      使用promise的话,就封装一个异步操作的函数,返回一个promise对象,
      一个Promise对应一个异步任务(一旦返回一个promise对象,就说明了启动了一个异步任务)
    // 2.1,回调地狱	
    doSomething(function (result) {
      doSomethingElse(result, function (newResult) {
        doThirdThing(newResult, function (finalResult) {
          console.log('Got the final result: ' + finalResult)
        }, failureCallback)
      }, failureCallback)
    }, failureCallback)
    //多个串联的异步操作:也就是说第一个弄完后才弄第二个

    // 2.2.使用 promise的链式调用解决回调地狱
    dosomething()
      //dosomething() 假如为一个封装的异步操作函数,返回的是promise对象,就是启动了异步任务! .then()为成功的回调,result为收到的结果
      .then(function (result) {//result为第一个promise返回的数据
        return dosomethingElse(result) //result为Promise.then的返回的结果(成功或失败,返回值为result),然后作为条件传入第二个回调函数(dosomethingElse)中作为条件,调用了第二个异步任务了
      })
      .then(function (newResult) { //newResult为第二个回调函数处理Promise.then的结果
        return doThirdThing(newResult) //作为参数传入,并且	调用了第三个异步任务了
      })
      .then(function (finalResult) { //这边的.then()为第三个异步任务的回调结果! --finalResult
        console.log('Got the final result:' + finalResult)
      })
      .catch(failurecallback)
    //优点:失败的回调都直接放置在最后,中间都是成功的回调! 异常传递(中间任何一环出错,这里都会可以打印出来)

//2.2实例代码
    //1:创建一个Promise对象
    const p = new Promise((resolve, reject) => {
      console.log(0); //执行器函数,为同步函数,优先执行
      //2:异步任务操作
      setTimeout(() => {
        let time = Date.now();
        if (time % 2 === 0) { //偶数成功,奇数失败
          resolve(1) //该Promise成功时,结果值为1,代表包裹这个resolve(1)的Promise的返回的结果为Promise对象和成功值为1
        } else {
          reject(2) //该Promise失败时,结果值为2
        }
      }, 1000)
    }).then(
      value => {//value为第一个Promise的成功值或失败值,作为参数传递进来到箭头函数
        console.log("onFulfilled1()", value);
        //return new Promise((resolve, reject) => {
          //resolve(1)
        //})
      },
      reason => {
        console.log("onRejected1()", reason);
      }
    )
    //结果为: 0 onFulfilled1() 1,要么 0 onRejected1() 2


    // 2.3 async/await: 回调地狱的终极解决方案(相比较promise,async/await从源码上来看没有回调函数)
    async function request() {
        try {
          const result = await doSomething() //这一段代码必须成功后,才会执行下面的代码,以此类推
          const newResult = await doSomethingElse(result)
          const finalResult = await doThirdThing(newResult)
          console.log('Got the final result' + finalResult)
        } catch (reason) {
          failureCallback(reason)
        }
    }

(3):Promise的API

1:promise语法糖

//需求:产生一个成功值为01的promise对象,并且调用其数据输出
// 01:采用语法糖定义一个promise对象
const p01 = Promise.resolve(01);
p01.then(value => {
  console.log(value);
})
//:02:采用语法糖+链式编程
Promise.resolve(02).then(value => {
  console.log(value);
})

2:Promise.all方法
返回的是一个promise对象,里面的为promise对象组成的数组形式或者可迭代的String

const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.reject(3);
假如三个异步任务都是成功的时候,才能获取到数据或继续向下执行,那么使用Promise.all方法极好! 有一个失败就会失败!
//const pAll = Promise.all([p1, p2, p3]); //里面参数为数组形式,p1-p3都为promise对象 结果,由于3为失败,调用onReject()执行reason()
const pAll = Promise.all([p1, p2]);
pAll.then(
  values => {
    console.log('onFulfill()', values);
  },
  reason => {
    console.log('onReject()', reason);
  }
)

3:Promise.race方法
Promise.race()方法,返回一个promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝 看谁先执行最快结束,就看它的结果!

const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.reject(3);
// const pRace = Promise.race([p1, p2, p3]); //结果为:race onFulfill() 1 因为都没有设置延迟,先执行1的 成功
const pRace = Promise.race([p3, p2, p1]); //结果为:race onReject() 3 因为都没有设置延迟,先执行3的 失败
pRace.then(
  values => {
    console.log("race onFulfill()", values);
  },
  reason => {
    console.log('race onReject()', reason);
  }
)

(4):Promise几个关键问题解析

1:Promise的状态

  1:resolve --- pending变为resolveed(确定),调用成功
  2:rejecte --- pending变为rejected(失败),调用失败
  3:抛出异常 --- 抛出异常后就是peding变为rejected

2:一个Promise指定多个成功、失败回调函数,都会调用吗?

  当promise改变状态的时候,都会调用!
    //1:创建一个promise对象 --- 里面传入一个执行器函数(同步的回调函数) 执行器函数里面有两个参数(resolve,reject)也是回调函数!
    const p1 = new Promise((resolve, reject) => {
      throw new Error;
      // throw 3; //抛出异常
    })
    p1.then( //指定回调函数
      value => {
        console.log();
      },
      reason => {
        console.log('reason', reason);
      }
    )
    p1.catch(
      reason => {
        console.log('reason2', reason);
      }
    )
    //结果:  reason Error  reason2 Error

3:改变promise状态还有指定回调函数是谁先谁后?

    (1)都有可能,正常情况下,先指定回调函数后在改变状态,但也可以先改变状态在指定回调函数
    (2)如何先改变状态再指定回调函数?
          01方法:在执行器函数中先调用resolve()/reject()
          02方法: 延迟更长时间才调用!
    (3)什么时候才能得到数据?
      01:如果先指定回调函数,那么当状态发生改变的时候,回调函数就被调用并且得到数据
      02:如果先改变状态,那当指定回调函数时,回调函数被调用后,得到数据
     注意点:.then方法里面的value,reason为异步回调函数!

先指定回调函数,再改promise状态

    //先指定回调函数,再改promise状态
    new Promise((resolve, reject) => {
      //执行异步任务
      setInterval(() => { //由于异步任务,有延迟1S,再改变状态(同时指定数据),异步执行回调函数
        resolve(1);
      }, 1000)
    }).then( //先指定回调函数 保存当前指定回调函数!
      value => { //注意点:这是异步回调函数
        console.log('onFulfilled', value);
      },
      reason => {
        console.log('onRejected', reason);
      }
    )

先改变promise状态,再指定回调函数

    //方式1:
    new Promise((resolve, reject) => {
      resolve(1); //先改变状态(同时指定数据)
    }).then( //再指定回调函数,异步执行回调函数(成功还是失败的回调)
      value => {
        console.log('value', value);
      },
      reason => {
        console.log('reason', reason);
      }
    )
    // 方式2
    const p1 = new Promise((resolve, reject) => {
      //执行异步任务
      setInterval(() => { //先改变状态(同时指定数据) 因为then延迟时间比这边长
        resolve(1);
      }, 1000)
    })
    setTimeout(() => {
      p1.then( //再指定回调函数,异步执行回调函数(成功还是失败的回调)
        value => {
          console.log('onFulfilled', value);
        },
        reason => {
          console.log('onRejected', reason);
        }
      )
    }, 1100)

4:Promise.then()返回的是一个新的promise(对象)的结果状态由谁决定?

    (1)简单表达:由.then方法指定的回调函数执行的结果决定!(就是调用.then方法的promise实例)
    (2)详细表达:
        01:如果抛出异常,新的promise变为rejected,reason为抛出的异常
        02:如果返回的是为promise的任意值,新的promise变为resolved,value值为返回的值
        03:如果返回一个新的promise对象,此promise的结果就会成为新的promise的结果!
 //1:请问下面的输出结果为?
    new Promise((resolve, reject) => {
      resolve(1);
      // reject(1);
    }).then( //由于上面new promise函数是失败的,所以调用.then的失败函数
      value => {
        console.log('onFulfiled()', value); //23行
        // return 2;
        // return Promise.resolve(3); //返回一个成功值为3的promise实例
        // return Promise.reject(4); //返回一个失败值为4的promise实例
        throw 5;
      },
      reason => {
        console.log('onRejected()', reason); //26行
      }
    ).then( //因为.then()返回的是一个新的promise对象,才能继续链式.then(), 这边的.then调用有上一层promise函数的执行后的结果!
      value => {
        console.log('onFulfiled2()', value); //30行
      },
      reason => {
        console.log('onRejected2()', reason); //33行
      }
    )
    //当resolve(1)时 --- 结果1为:由于执行了23行和30行 onFulfiled() 1  onFulfiled2() undefined 
    // 解析:为何30行代码输出undefined?,这是因为这边的.then方法是上一层promise函数执行后,却没有返回任何值,也就是undefined
    //若是在23行下添加一个return 2; 那么其结果将会变为onFulfiled2() 2,而非未定义! 若是return Promise.resolve(3); 那么其结果为onFulfiled2()3
    //若返回的是return Promise.reject(4),结果为onRejected2() 4 若是抛出异常throw 5;  结果为:onRejected2() 5

    //就是啊第一个promise执行的是成功,值为1,调用.then后,这个值1为执行结果(首先先判断成功还是失败),
    // 成功时候,就调用下一个.then中成功的回调函数(里面在返回一个值或者新的promise,为调用.then的判断条件!)

//当reject(1)时  执行的是26行,还有30行 ---结果为: onRejected() 1 ,onFulfiled2() undefined

5:Promise如何串联多个操作任务?

    01:promise的then()返回一个新的promise对象,可以看成.then()的链式调用
    02:通过then的链式调用串联多个同步/异步任务!
new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log('执行任务1(异步)');
        resolve(1); //成功的回调,指定数据为1 ---这边是promise.then()后在输入结果,也就是任务1的结果!
        // (成功的时候,调用OnFulfilled(),也就是value =>{} value就是成功的值!
      }, 1000)
    }).then(
      value => {
        console.log('任务1的结果为:', value);
        console.log("执行任务2(同步)");
        return 2;
      }
    ).then(
      value => {
        console.log("任务2的结果为:", value);
        //异步任务需要封装在一个promise对象里面,并且需要确定promise的状态(也就是resolve(3))
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            console.log('执行任务3(异步)');
            resolve(3);
          }, 1000)
        })
      }
    ).then(
      value => {
        console.log("任务3的结果为:", value);
      }
    )
    //注意点:一旦是异步任务的就需要包裹在一个promise对象里面!
    //结果:执行任务1(异步) 任务1的结果为: 1
    // 执行任务2(同步) 任务2的结果为: 2
    //  执行任务3(异步) 任务3的结果为: 3

6:promise的异常传透?

    01:当使用promise的then链式调用时,可以在最后指定失败的回调
    02:前面的任何操作异常,都会传到最后的失败的回调函数中处理!
 new Promise((resolve, reject) => {
      // resolve(1);
      reject(1);
    }).then(
      value => {
        console.log("onFulfilled1()", value);
        return 2;
      },
      // resoan => {
      //   throw reason
      // }
      // reason => Promise.reject(reason) //也可以自己抛出异常
    ).then(
      value => {
        console.log("onFulfilled2()", value);
        return 3;
      }
    ).then(
      value => {
        console.log("onFulfilled3()", value);
        return 4;
      }
    ).catch(
      reason => {
        console.log("onRejected1()", reason);
      }
    )
    //执行结果:onRejected1() 1
    //执行流程:第一个promise执行的时候reject(1)失败,在调用.then方法时候,就是执行失败的回调(也就是reason =>{)},
    //但是若是这边.then()没有写reason =>{。。。},里面会自动帮你补上reason =>{throw reason},然后这边的结果依然是失败状态,继续往下面传透失败的回调结果!
    //注意点:反正就是一个promise对象状态为成功时(指定了数据),并且在.then方法中调用成功的回调,失败也是同理!

7:中断promise链?

    01:当使用promise的链式调用时,在中间中断,不在调用后面的回调函数
    02:办法:在回调函数中返回一个pendding状态的promise对象
 new Promise((resolve, reject) => {
      // resolve(1);
      reject(1);
    }).then(
      value => {
        console.log("onFulfilled1()", value);
        return 2;
      },
      // resoan => {
      //   throw reason
      // }
      // reason => Promise.reject(reason) //也可以自己指定要返回的异常!
    ).then(
      value => {
        console.log("onFulfilled2()", value);
        return 3;
      }
    ).then(
      value => {
        console.log("onFulfilled3()", value);
        return 4;
      }
    ).catch(
      reason => {
        console.log("onRejected1()", reason);
        // throw reason;
        return Promise.reject(reason);
        //这边继续链式.then方法后,需要返回失败的回调,不然就直接调用成功的!后面添加一个新的promise,状态为pedding,直接中断
        // return new Promise(() => {})
      }
    ).then(
      value => {
        console.log("onFulfilled3()", value);
        return 4;
      },
      reason => {
        console.log("onRejected2()", reason);
      }
    )
    //结果:不添加什么就 onRejected1() 1, onFulfilled3() undefined 若是添加失败的回调就:onRejected1() 1 onRejected2() 1
    //结果: return new Promise(() => {})-添加了 onRejected1() 1

三、自定义一个promise的各种方法解析

(1):自定义promise的准备工作

新建一个lib库用于存放自己自定义的promise.js文件
然后向外暴露promise函数,以供外面调用,这就需要使用到ES5中的立即执行函数来导出promise模块
注意点:立即执行函数传入window,是为了让promise函数暴露出来
需要在执行器函数内部定义状态,数据,还有回调函数的缓存!
01:还有需要定义一下,promise的初始状态为pending
02:给promise指定一个存储结果数据的属性
03:定义一个回调函数里面存放着可能待执行的函数(缓存回调函数)
this.callbacks = []; //每一个元素的结构:{onFulfilled(){},onRejected(){}}
04:指定执行器函数和resolve,reject函数同步执行(也就是执行器函数调用这两个函数)!

/*
自定义Promise函数模块
 */
// 使用ES5的模块化 ---立即执行函数
(function (window) {

  /*
    Promise构造函数
    executor:执行器函数
   */
  function Promise(executor) {

    this.status = 'pending'; //给promise对象指定status属性,初始值为pending
    this.data = undefined; //给promise指定一个存储结果数据的属性
    this.callbacks = []; //每一个元素的结构:{onFulfilled(){},onRejected(){}}

    function resolve(value) {

    }

    function reject(reason) {

    }
    //因为使用的时候,在executor执行器函数里面传入了两个回调函数,需要在这边定义一下!
    //立即同步执行exxcutor 
    executor(resolve, reject);

  }
  /*Promise原型对象的then() 
  指定成功和失败的回调函数,并且返回一个新的promise对象
  */
  Promise.prototype.then = function (onFulfilled, onRejected) {

  }

  /*Promise原型对象的catch()
  指定失败的回调函数,并且返回一个新的promise对象
   */
  Promise.prototype.catch = function (onRejected) {

  }

  /*Promise函数对象的resolve方法 
  返回一个指定结果成功值为value的promise
  */
  Promise.resolve = function (value) {

  }

  /*Promise函数对象的reject方法
  返回的是一个指定结果失败值为reason的promise
   */
  Promise.reject = function (reason) {

  }

  /*Promise函数对象的all方法   all方法里面参数是promise对象组成的数组!
  返回的是一个promise,只有数组中的promise都成功的时候才成功,否则有一个失败,就失败!
  */
  Promise.all = function (Promises) {

  }

  /*Promise函数对象的race方法   race方法里面参数是promise对象组成的数组!
  返回的是一个promise,其结果有数组中的promise对象,先完成的promise决定!
  */
  Promise.race = function (Promises) {

  }

  //向外暴露Promise函数
  window.Promise = Promise
})(window)

(2):对于执行器函数内部的定义

首先Promise是个函数,它需要传一个function,就是执行器函数(executor),就相当于我们使用Promise时那个new Promise(function(resolve,reject))中的function()
然后执行器函数里面有两个参数,就是resolve和reject,分别对应的是成功的回调还有失败的回调

因此执行器函数由三部分组成:分别为resolve函数,reject函数,executor同步执行函数
1:resolve函数-代表的是成功时
2:reject函数-代表是失败的时
3:executor函数-执行函数的时候,连带resolve和reject绑定在一起,先被调用执行谁
注意点:需要在resolve和reject函数里面先判断promise状态是否为pending状态,假如不是,直接结束掉,也就是return;
// 因为状态只能改变一次!,一进来就是reject(或resolve)就执行,若是pending就直接结束掉!

  // Promise构造函数  executor:执行器函数
  function Promise(executor) {

    const that = this; //把that指向promise的that存再一个变量中,需要用的时候,就调用!
    that.status = 'pending'; //给promise对象指定status属性,初始值为pending
    that.data = undefined; //给promise指定一个存储结果数据的属性
    that.callbacks = []; //定义一个回调函数里面存放着可能待执行的函数,每一个元素的结构:{onFulfilled(){},onRejected(){}}

    function resolve(value) {
      //00:需要先判断 当前状态是否是pending,如果不是直接结束掉
      if (that.status != 'pending') {
        return
      }

      //01:将状态改为resolved
      that.status = 'resolved'
      //保存value数据
      that.data = value;

      //:02:如果有待执行callback函数,立即异步执行回调函数onFulfilled()(丢到任务队列中)
      if (that.callbacks.length > 0) {
        setTimeout(() => { //03:放入队列中,执行所有成功的回调
          that.callbacks.forEach(callbacksObj => { //遍历出回调函数数组中是否有成功的回调函数
            callbacksObj.onFulfilled(value); //给成功的回调函数指定成功的结果!
          });
        })
      }
    }

    function reject(reason) {
      //需要先判断 当前状态是否是pending,如果不是直接结束掉
      if (that.status != 'pending') {
        return
      }
      that.status = "rejected"
      that.data = reason;
      if (that.callbacks.length > 0) {
        setTimeout(() => {
          that.callbacks.forEach(callbacksObj => {
            callbacksObj.onRejected(reason)
          })
        }, 1000)
      }

    }
    //因为使用的时候,在executor执行器函数里面传入了两个回调函数,需要在这边定义一下!
    //立即同步执行exxcutor 
    try {
      executor(resolve, reject);
    } catch (error) { //然后执行器抛出异常,那么就调用reject失败函数
      reject(error)
    }
  }

(3):对于promise.prototype.then()函数的定义

Promise原型对象的then()
功能:返回一个新的promise对象,并且指定成功和失败的回调函数,
01:返回一个新的prmise对象,使用new Promise里面传入执行器函数
02:并且指定成功和失败的回调函数,那么需要在执行器函数里面
03:在执行器函数里面,就行需要根据promise的状态处于哪个状态来输出结果
001:当前promise的状态为pending时候,将回调函数数据保存起来!
002:如果为resolve成功,那么便调用成功的回调函数(异步任务哦,需要定时器)
003:如果是rejected状态的,失败就需要调用失败的回调函数onRejected()
注意点:that=this;是为了把指向promise的保存起来,避免this指向问题

难点:   promise的结果有着以下三种情况,因此需要补货异常  
  01:如果抛出异常,return的promise就会失败,其reason就是error
  02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
  03:如果回调函数返回的是promise对象(而promise的结果在.then输出,于是需要借用.then方法),那么return的结果就是这个promise的结果(是成功就成功,是失败就失败) 
使用try来补货promise的返回结果(promise对象):这就需要判断是对象还是非对象,使用到instanceof方法,

准备01

/*Promise原型对象的then() 
  返回一个新的promise对象,并且指定成功和失败的回调函数,
  */
  Promise.prototype.then = function (onFulfilled, onRejected) { //onFulfilled形式参数,接受外面的成功的回调,然后指向resolve
    const that = this;

    // 01:返回一个新的promise对象
    return new Promise((resolve, reject) => { //根据里面的状态执行结果,来判断是应该调用成功的回调还是失败的回调
      //02:根据promise的状态来输出结果!
      if (that.status === PENDING) { //假设promise的状态为pending时候,将回调函数数据保存起来!
        that.callbacks.push({
          onFulfilled,
          onRejected
        })
      } else if (that.status === RESOLVED) { //如果为resolve成功,那么便调用成功的回调函数(异步任务哦,需要定时器),传入里面的value
        setTimeout(() => {
          /*
          01:如果抛出异常,return的promise就会失败,其reason就是error
          02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
          03:如果回调函数返回的是promise对象(而promise的结果在.then输出,于是需要借用.then方法),
               那么return的结果就是这个promise的结果(是成功就成功,是失败就失败)
           */
          //注意点1:新的promise的结果,由onFulfilled或onRejected来决定的!
          //注意点2:onFulfilled函数或onRejected函数执行后,根据结果来调用resolve还是reject
          //注意点3:一旦调用了resolve那么返回的promise就是成功,反之亦然就是失败
          //采用捕获的方式,去查看是否抛出异常
          try {
            const result = onFulfilled(that.data); //成功就调用onFulfilled函数( 捕获传递进来的,返回一个promise
            if (result instanceof Promise) { //03:如果回调函数返回的是promise对象,那么return的结果就是这个promise的结果
              //因为result这这边是promise对象,采用promise.then的方法指定成功的回调还有失败的回调!
              result.then(
                value => {
                  resolve(value); //当result成功,让return的promise也成功,这就需要调用resolve并且指定成功;
                },
                reason => {
                  reject(reason); //当result失败,让return的promise也失败,这就需要调用resolve并且指定失败;
                }
              )
            } else { //02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
              resolve(result); //值就是捕获到的结果!
            }
          } catch (error) {
            reject(error)
          }

        })
      } else { //rejected状态的,失败就需要调用失败的回调函数onRejected()
        setTimeout(() => {
          try {
            const result = onRejected(that.data);
            if (result instanceof Promise) {
              result.then(
                value => {
                  resolve(value); //当result成功,让return的promise也成功,这就需要调用resolve并且指定成功;
                },
                reason => {
                  reject(reason); //当result失败,让return的promise也失败,这就需要调用resolve并且指定失败;
                }
              )
            } else { //02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
              resolve(result); //值就是捕获到的结果!
            }
          } catch (error) {
            reject(error)
          }
        })
      }
    })

  }

准备01的简介版

就是在方式的1基础上,对以下这几行代码进行优化

如果回调函数返回的是promise对象(而promise的结果在.then输出,于是需要借用.then方法),那么return的结果就是这个promise的结果(是成功就成功,是失败就失败)
方式1解析:就是Promise对象的成功值为value,其结果为value,然后这个返回的promise的结果根据前面的promise(对象)结果决定的,于是就直接调用resolve并且传递了value即可!
方式2:就是既然第一个promise对象的结果作为条件给了第二个promise的结果,并且还调用了resolve的方式来传值,何不如直接把使用第一个promise调用then方法,里面传递两个回调函数,参数依旧照旧传递即可,这样去掉了外层的函数,效率也就提高了!

 if (result instanceof Promise) {
               // result.then(
              //   value => {
              //     resolve(value)
              //   },
              //   reason => {
              //     reject(reason)
              //   }
              // )
     //上面的代码简洁为下面的一行代码:
     //解析:
     result.then(resolve, reject);
 }

准备02:在01基础上增加条件

由于捕获异常在resolve,reject,还有pending状态的时候保存数据都使用到,因此把这个封装为一个函数(handle),就是调用指定的回调函数处理,根据执行的结果,改变return的promise状态
handel的参数为传入的回调函数-callback;
调用的时候:直接使用handle(成功时候调用的是-onFulfilled),失败的时候调用时onRejected

/*Promise原型对象的then() 
  返回一个新的promise对象,并且指定成功和失败的回调函数,
  */
  Promise.prototype.then = function (onFulfilled, onRejected) { //onFulfilled形式参数,接受外面的成功的回调,然后指向resolve

    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value; //向后面传递value
    onRejected = typeof onRejected === 'function' ? onRejected : reason => {
      throw reason; //指定默认的失败回调,并且将异常穿透下去(向后面传递失败的reason)
    }
    const that = this;

    // 01:返回一个新的promise对象
    return new Promise((resolve, reject) => { //根据里面的状态执行结果,来判断是应该调用成功的回调还是失败的回调
      /*
        调用指定的回调函数处理,根据执行的结果,改变return的promise状态
       */
      function handle(callback) { //handle---处理
        /*
          01:如果抛出异常,return的promise就会失败,其reason就是error
          02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
          03:如果回调函数返回的是promise对象(而promise的结果在.then输出,于是需要借用.then方法),
              那么return的结果就是这个promise的结果(是成功就成功,是失败就失败)
         */
        //注意点1:新的promise的结果,由onFulfilled或onRejected来决定的!
        //注意点2:onFulfilled函数或onRejected函数执行后,根据结果来调用resolve还是reject
        //注意点3:一旦调用了resolve那么返回的promise就是成功,反之亦然就是失败
        //采用捕获的方式,去查看是否抛出异常
        try {
          const result = callback(that.data); //成功就调用onFulfilled函数( 捕获传递进来的,返回一个promise
          if (result instanceof Promise) { //03:如果回调函数返回的是promise对象,那么return的结果就是这个promise的结果
            //因为result这这边是promise对象,采用promise.then的方法指定成功的回调还有失败的回调!
            result.then(
              value => {
                resolve(value); //当result成功,让return的promise也成功,这就需要调用resolve并且指定成功;
              },
              reason => {
                reject(reason); //当result失败,让return的promise也失败,这就需要调用resolve并且指定失败;
              }
            )
          } else { //02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
            resolve(result); //值就是捕获到的结果!
          }
        } catch (error) {
          reject(error)
        }
      }

      //02:根据promise的状态来输出结果!
      if (that.status === PENDING) { //当前promise的状态为pending时候,将回调函数数据保存起来!
        that.callbacks.push({
          onFulfilled(value) { //这边是在上面的callbacksObj.onFulfilled(value) 调用该函数的
            handle(onFulfilled);
          },
          onRejected(reason) { //这边是在上面的callbacksObj.onRejected(reason) 调用该函数的
            handle(onRejected);
          }
        })
      } else if (that.status === RESOLVED) { //如果为resolve成功,那么便调用成功的回调函数(异步任务哦,需要定时器),
        // 异步执行onFulfilled并且改变return的promise的状态(这是在handle封装函数内部改的)
        setTimeout(() => {
          handle(onFulfilled);
        })
      } else { //如果是rejected状态的,失败就需要调用失败的回调函数onRejected(),异步执行onRejected(),并且改变return的promise的状态
        setTimeout(() => {
          handle(onRejected);
        })
      }
    })

  }

(4):Promise原型对象的catch()的定义

  /*Promise原型对象的catch()
  指定失败的回调函数,并且返回一个新的promise对象
   */
  Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected);
    //前面undefined是为了往后面传递value,而onRejected直接异常穿透下去
    
    //这是在上面的定义的来处理的
    //onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value; //向后面传递value
    //onRejected = typeof onRejected === 'function' ? onRejected : reason => {
     // throw reason; //指定默认的失败回调,并且将异常穿透下去(向后面传递失败的reason)
    }
  }

(5):Promise函数对象的resolve方法和reject方法的定义

  /*Promise函数对象的resolve方法 
  返回一个指定结果成功值为value的promise
  */
  Promise.resolve = function (value) {
    //返回的新的promise,但是指定结果可能成功或者失败
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) { //是promise对象,那么其value的结果作为新的promise对象的结果,
        value.then(resolve, reject)
      } else { //不是promise对象,状态变为resolve,那么其数据就是value
        resolve(value);
      }
    })
  }

  /*Promise函数对象的reject方法
  返回的是一个指定结果失败值为reason的promise
   */
  Promise.reject = function (reason) {
    //返回一个新的promise对象,并且指定失败的结果
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }

(6):Promise函数对象的all方法

all方法里面参数是promise对象组成的数组!
返回的是一个新的promise,只有数组中的promise都成功的时候才成功,否则有一个失败,就失败!

Promise.all = function (Promises) {
    let resolveCount = 0; //定义一个计数器,用来保存promise成功的次数
    const values = new Array(Promises.length); //这个数组是用来保存所有成功的promise对象组成的数组 创建数组并且指定长度
    return new Promise((resolve, reject) => {
      //遍历取出promised数组中的每一个promise对象
      Promises.forEach((p, index) => {
        //注意点:考虑到参数可能不是promise对象,隐藏把这个p外面套一个promise.resolve,反正这个返回的是一个promise结果,直接调用.then也可以
        Promise.resolve(p).then(
          value => {
            resolveCount++; //一进入这里(代表成功),就++
            //p成功了,那么将成功的value保存在values数组里面
            // values.push(value);//不能直接push,因为为了使得promise对象的顺序照旧
            values[index] = value; //就是遍历每一个元素,存储对应的下标进入数组values
            //如果全部成功了,将return的promise改变为成功
            if (resolveCount === Promises.length) {
              resolve(values);
            }
          },
          reason => { //只要有一个失败,return的promise就是失败
            reject(reason)
          }
        )
      })
    })
  }

(7):Promise函数对象的race方法

race方法里面参数是promise对象组成的数组!
返回的是一个promise,其结果有数组中的promise对象,结果由先最先完成的promise决定!

  Promise.race = function (Promises) {
    return new Promise((resolve, reject) => {
      Promises.forEach((p, index) => {
        Promise.resolve(p).then(
          value => { //一旦成功了,那么成功的promise对象的值,就return成功,并且把成功的值为value
            resolve(value);
          },
          reason => { //一旦失败了,那么失败的promise对象的值,就return失败,并且把失败的值为reason
            reject(reason);
          }
        )
      })
    })
  }

(8):在promise.js里面自定义自己的方法

01:Promise.resolveDelay 返回一个promise对象,在指定时间后才确定结果(可能成功或失败)
02:Promise.rejectDelay 返回一个promise对象,在指定时间后才确定失败

/*01:Promise.resolveDelay 返回一个promise对象,在指定时间后才确定结果(可能成功或失败) */
  Promise.resolveDelay = function (value, time) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (value instanceof Promise) { //value就是这个返回的结果,可能是promise对象,可能不是
          value.then(resolve, reject)
          // value.then(
          //   value => {
          //     resolve(value)
          //   },
          //   reason => {
          //     reject(reason)
          //   }
          // )
        } else {
          resolve(value)
        }
      })
    }, time)
  }

  /*02:Promise.rejectDelay 返回一个promise对象,在指定时间后才确定失败 */
  Promise.rejectDelay = function (reason, time) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(reason);
      }, time)
    })
  }

四:手写一个promise方法的完整代码如下

/*
自定义Promise函数模块
 */
(function (window) {
  const PENDING = "peding";
  const RESOLVED = "resolve";
  const REJECTED = "reject";

  // Promise构造函数  executor:执行器函数
  function Promise(executor) {

    const that = this; //把that指向promise的that存再一个变量中,需要用的时候,就调用!
    that.status = PENDING; //给promise对象指定status属性,初始值为pending
    that.data = undefined; //给promise指定一个存储结果数据的属性
    that.callbacks = []; //定义一个回调函数里面存放着可能待执行的函数,每一个元素的结构:{onFulfilled(){},onRejected(){}}

    function resolve(value) {
      //04:需要先判断 当前状态是否是pending,如果不是直接结束掉
      if (that.status != PENDING) {
        return
      }

      //01:将状态改为resolved
      that.status = RESOLVED
      //保存value数据
      that.data = value;

      //02:如果有待执行callback函数,立即异步执行回调函数onFulfilled()(丢到任务队列中)
      if (that.callbacks.length > 0) {
        setTimeout(() => { //03:放入队列中,执行所有成功的回调
          that.callbacks.forEach(callbacksObj => { //遍历出回调函数数组中是否有成功的回调函数
            callbacksObj.onFulfilled(value); //给成功的回调函数指定成功的结果!
          });
        })
      }
    }

    function reject(reason) {
      //需要先判断 当前状态是否是pending,如果不是直接结束掉 
      // 因为状态只能改变一次!,一进来就是reject就执行,若是pending就直接结束掉!
      if (that.status != PENDING) {
        return
      }
      that.status = REJECTED
      that.data = reason;
      if (that.callbacks.length > 0) {
        setTimeout(() => {
          that.callbacks.forEach(callbacksObj => {
            callbacksObj.onRejected(reason)
          })
        }, 1000)
      }

    }
    //因为使用的时候,在executor执行器函数里面传入了两个回调函数,需要在这边定义一下!
    //立即同步执行exxcutor 
    try {
      executor(resolve, reject);
    } catch (error) { //然后执行器抛出异常,那么就调用reject失败函数
      reject(error)
    }
  }

  /*Promise原型对象的then() 
  返回一个新的promise对象,并且指定成功和失败的回调函数,
  */
  Promise.prototype.then = function (onFulfilled, onRejected) { //onFulfilled形式参数,接受外面的成功的回调,然后指向resolve

    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value; //向后面传递value
    onRejected = typeof onRejected === 'function' ? onRejected : reason => {
      throw reason; //指定默认的失败回调,并且将异常穿透下去(向后面传递失败的reason)
    }
    const that = this;

    // 01:返回一个新的promise对象
    return new Promise((resolve, reject) => { //根据里面的状态执行结果,来判断是应该调用成功的回调还是失败的回调
      /*
        调用指定的回调函数处理,根据执行的结果,改变return的promise状态
       */
      function handle(callback) { //handle---处理
        /*
          01:如果抛出异常,return的promise就会失败,其reason就是error
          02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
          03:如果回调函数返回的是promise对象(而promise的结果在.then输出,于是需要借用.then方法),
              那么return的结果就是这个promise的结果(是成功就成功,是失败就失败)
         */
        //注意点1:新的promise的结果,由onFulfilled或onRejected来决定的!
        //注意点2:onFulfilled函数或onRejected函数执行后,根据结果来调用resolve还是reject
        //注意点3:一旦调用了resolve那么返回的promise就是成功,反之亦然就是失败
        //采用捕获的方式,去查看是否抛出异常
        try {
          const result = callback(that.data); //成功就调用onFulfilled函数( 捕获传递进来的,返回一个promise
          if (result instanceof Promise) { //03:如果回调函数返回的是promise对象,那么return的结果就是这个promise的结果
            //因为result这这边是promise对象,采用promise.then的方法指定成功的回调还有失败的回调!
            result.then(
              value => {
                resolve(value); //当result成功,让return的promise也成功,这就需要调用resolve并且指定成功;
              },
              reason => {
                reject(reason); //当result失败,让return的promise也失败,这就需要调用resolve并且指定失败;
              }
            )
          } else { //02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
            resolve(result); //值就是捕获到的结果!
          }
        } catch (error) {
          reject(error)
        }
      }

      //02:根据promise的状态来输出结果!
      if (that.status === PENDING) { //当前promise的状态为pending时候,将回调函数数据保存起来!
        that.callbacks.push({
          onFulfilled(value) { //这边是在上面的callbacksObj.onFulfilled(value) 调用该函数的
            handle(onFulfilled);
          },
          onRejected(reason) { //这边是在上面的callbacksObj.onRejected(reason) 调用该函数的
            handle(onRejected);
          }
        })
      } else if (that.status === RESOLVED) { //如果为resolve成功,那么便调用成功的回调函数(异步任务哦,需要定时器),
        // 异步执行onFulfilled并且改变return的promise的状态(这是在handle封装函数内部改的)
        setTimeout(() => {
          handle(onFulfilled);
        })
      } else { //如果是rejected状态的,失败就需要调用失败的回调函数onRejected(),异步执行onRejected(),并且改变return的promise的状态
        setTimeout(() => {
          handle(onRejected);
        })
      }
    })

  }

  /*Promise原型对象的catch()
  指定失败的回调函数,并且返回一个新的promise对象
   */
  Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected);
    //前面undefined是为了往后面传递value,而onRejected直接异常穿透下去
  }

  /*Promise函数对象的resolve方法 
  返回一个指定结果成功值为value的promise
  */
  Promise.resolve = function (value) {
    //返回的新的promise,但是指定结果可能成功或者失败
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) { //是promise对象,那么其value的结果作为新的promise对象的结果,
        value.then(resolve, reject)
      } else { //不是promise对象,状态变为resolve,那么其数据就是value
        resolve(value);
      }
    })
  }

  /*Promise函数对象的reject方法
  返回的是一个指定结果失败值为reason的promise
   */
  Promise.reject = function (reason) {
    //返回一个新的promise对象,并且指定失败的结果
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }

  /*Promise函数对象的all方法   all方法里面参数是promise对象组成的数组!
  返回的是一个promise,只有数组中的promise都成功的时候才成功,否则有一个失败,就失败!
  */
  Promise.all = function (Promises) {
    let resolveCount = 0; //定义一个计数器,用来保存promise成功的次数
    const values = new Array(Promises.length); //这个数组是用来保存所有成功的promise对象组成的数组 创建数组并且指定长度
    return new Promise((resolve, reject) => {
      //遍历取出promised数组中的每一个promise对象
      Promises.forEach((p, index) => {
        //注意点:考虑到参数可能不是promise对象,隐藏把这个p外面套一个promise.resolve,反正这个返回的是一个promise结果,直接调用.then也可以
        Promise.resolve(p).then(
          value => {
            resolveCount++; //一进入这里(代表成功),就++
            //p成功了,那么将成功的value保存在values数组里面
            // values.push(value);//不能直接push,因为为了使得promise对象的顺序照旧
            values[index] = value; //就是遍历每一个元素,存储对应的下标进入数组values
            //如果全部成功了,将return的promise改变为成功
            if (resolveCount === Promises.length) {
              resolve(values);
            }
          },
          reason => { //只要有一个失败,return的promise就是失败
            reject(reason)
          }
        )
      })
    })
  }

  /*Promise函数对象的race方法   race方法里面参数是promise对象组成的数组!
  返回的是一个promise,其结果有数组中的promise对象,先完成的promise决定!
  */
  Promise.race = function (Promises) {
    return new Promise((resolve, reject) => {
      Promises.forEach((p, index) => {
        Promise.resolve(p).then(
          value => { //一旦成功了,那么成功的promise对象的值,就return成功,并且把成功的值为value
            resolve(value);
          },
          reason => { //一旦失败了,那么失败的promise对象的值,就return失败,并且把失败的值为reason
            reject(reason);
          }
        )
      })
    })
  }

  /*
    在promise.js里面自定义自己的方法:
   */

  /*01:Promise.resolveDelay 返回一个promise对象,在指定时间后才确定结果(可能成功或失败) */
  Promise.resolveDelay = function (value, time) {

    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (value instanceof Promise) { //value就是这个返回的结果,可能是promise对象,可能不是
          value.then(resolve, reject)
          // value.then(
          //   value => {
          //     resolve(value)
          //   },
          //   reason => {
          //     reject(reason)
          //   }
          // )
        } else {
          resolve(value)
        }
      })
    }, time)
  }

  /*02:Promise.rejectDelay 返回一个promise对象,在指定时间后才确定失败 */
  Promise.rejectDelay = function (reason, time) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(reason);
      }, time)
    })
  }


  //向外暴露Promise函数
  window.Promise = Promise
})(window)

/*
  在promise方法里面自定义自己的方法:
 */

五:promise的面试题目

上一篇:LeetCode-68-文本左右对齐


下一篇:Promise学习笔记