Promise从入门到自定义

第一章:准备

1.1 区别函数对象和实例对象

<script>
    /*
      函数对象与实例对象
      函数对象:将函数作为对象使用时,简称为函数对象
      实例对象:new 函数产生的对象,简称为对象
    */
   function Fn() { // Fn函数

   }
   const fn = new Fn(); // new完之后,此时的Fn是构造函数,fn是实例对象(简称对象)
   console.log(Fn.prototype); // Fn是函数对象,体现对象特点是用.
   Fn.bind({}) // 调用函数对象的bind方法
   $('#test') // $是jQuery函数,()的左边是函数
   $.get('/test')  // $是jQuery函数对象,调用$函数对象的get方法
  </script>

在这里插入图片描述

1.2 两种类型的回调函数

<script>
    /*
    1)同步回调:
    理解:立即执行,完全执行了才结束,不会放入回调队列中
    例子:数组遍历相关的回调函数 / Promise的excutor函数
    2)异步回调:
    理解:不会立即执行,会放入回调队列中将来执行
    例子:定时器回调 / ajax回调 / Promise的成功|失败的回调
    */
   // 1.同步回调函数
   const arr = [1, 3, 5,];
   arr.forEach(item => { // 遍历回调,同步回调函数,不会放入队列中,一上来就要执行
    console.log(item);
   });
   console.log('forEach()之后');
   // 打印的结果:1 3 5 forEach()之后

   // 2.异步回调函数
   setTimeout(() => { // 异步回调函数,会放入队列中将来执行
     console.log('timeout callback()');
   }, 0);
   console.log('setTimeout()之后');
   // 打印的结果:setTimeout()之后 timeout callback()
  </script>

1.3 JS的error处理

<script>
    /*
      MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Error
      1.错误的类型
        Error: 所有错误的父类型
        ReferenceError: 引用的变量不存在
        TypeError: 数据类型不正确的错误
        RangeError: 数据值不在其所允许的范围内
        SyntaxError: 语法错误
      2.错误处理
        捕获错误: try...catch
        抛出错误: throw error
      3.错误对象
        message属性:错误相关信息
        stack属性:函数调用栈记录信息
    */

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

    // 2)TypeError: 数据类型不正确的错误
    let b = null;
    console.log(b.xxx); // Uncaught TypeError: Cannot read property 'xxx' of null

    // 3)RangeError: 数据值不在其所允许的范围内
    function fn() {
      fn()
    }
    fn() // Uncaught RangeError: Maximum call stack size exceeded

    // 4)SyntaxError: 语法错误
    const c = """"; // Uncaught SyntaxError: Unexpected string

    // 2.错误处理
    // 1)捕获错误: try...catch
    try {
      let d;
      console.log(d.xxx);
    } catch(error) { // error是一个对象,里面有两个属性。message和stack
      console.log(error.message);
      console.log(error.stack);
    } // TypeError: Cannot read property 'xxx' of undefined

    // 2)抛出错误: throw error
    function something() {
      if (Date.now() % 2 === 1) {
        console.log('当前时间为奇数,可以执行任务');
      } else { // 如果时间是偶数出现异常,由调用来处理
        throw new Error('当前时间为偶数,无法执行任务')
      }
    }
    // 捕获处理异常
    try {
      something();
    } catch(error) {
      alert(error.message);
    }
  </script>

第二章 Promise的理解和使用

2.1 Promise是什么?

2.1.1 理解

1.抽象表达:Promise是JS中进行异步编程的新的解决方案(旧的是使用纯回调)。
2.具体表达:
(1)从语法上来说:Promise是一个构造函数(即需要实例)。
(2)从功能上来说:Promise对象用来封装一个异步操作并可以获取骑异步结果。

2.1.2 Promise的状态改变
  1. pending变为resolved
  2. pendind变为rejected
    说明:只有这2种,且一个promise对象只能改变一次。无论变成成功还是失败,都会有一个结果数据。成功的数据一般称为value,失败的结果数据一般称为reason。
2.1.3 promise的基本流程

在这里插入图片描述

2.1.4 promise的基本使用
  <script>
    // 1.创建一个新的promise对象
    const p = new Promise((resolve, reject) => { // 执行器函数 同步回调
      // 2.执行异步操作函数
      console.log('执行 excutor');
      setTimeout(() => {
        const time = Date.now();
        if (time % 2 === 0) {
          // 3.1 如果成功了,调用resolve(value)
          resolve('成功的数据,time=' + time);
        } else {
          // 3.2 如果失败了,调用reject(reason)
          reject('失败的数据,time=' + time);
        }
      }, 1000);
    })

    console.log('new Promise() 之后');

    p.then(
      value => { // 接收得到成功的value
        console.log('成功的回调', value);
      },
      reason => { // 接收得到失败的reason
        console.log('失败的回调', reason);
      }
    );
    // 或者这样写
    // p.then(
    //   value => { // 接收得到成功的value
    //     console.log('成功的回调', value);
    //   },
    // )
    // .catch(
    //   reason => { // 接收得到失败的reason
    //     console.log('失败的回调', reason);
    //   }
    // );
  </script>

2.2 为什么要用promise?

2.2.1 指定回调函数的方式更加灵活
2.2.2 支持链式调用,可以解决回调地狱问题
<script>
    /*
    1.指定回调函数的方式更加灵活:(在面试中一般都会忽略这个,但其实这个是很重要的,可以检测你是否真的理解了promise)
      旧的:必须在启动异步任务之前指定
      promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数
    2.支持链式调用,可以解决回调地狱问题
      什么是回调地狱?回调函数嵌套使用,外部回调函数异步执行的结果是嵌套的回调函数执行的条件
      回调地狱的缺点?不便于阅读/不方便异常处理
      解决方案?promise链式调用
      终极解决方案?async/await
    */

    // 成功的回调函数
    function successCallback(result) {
      console.log('声音文件创建成功:' + result);
    }

    function failureCallback(error) {
      console.log('声音文件创建失败:' + error);
    }

    /*
    1.1使用纯回调函数
    */
    createAudioFileAsync(audioSettings, successCallback, failureCallback)

    /*
    1.2使用纯回调函数
    */
    const promise = createAudioFileAsync(audioSettings);
    setTimeout(() => {
      promise.then(successCallback, failureCallback);
    }, 3000);

    /*
    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().then(function (result) {
      return doSomethingElse(result)
    })
      .then(function (newResult) {
        return doThirdThing(newResult)
      })
      .then(function (finalResult) {
        console.log('Got the final result:' + finalResult);
      })
      .catch(failureCallback)

    /*
     2.3 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 (error) {
        failureCallback(error)
      }
    }
  </script>

2.3 如何使用promise?

2.3.1 Promise的API
  <script>
    /*
      1.Promise构造函数: Promise (excutor) {}
        excutor函数:同步执行 (resolve, reject) => {}
        resolve函数:内部定义成功时我们调用的函数 value => {}
        reject函数:内部定义失败时我们调用的函数 reason => {}

      2.Promise.prototype.then方法:(onResolved, onRejected) => {}
        onResolved函数:成功的回调函数 value => {}
        onRejected函数:失败的回调函数 reason => {}
        说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个的promise对象

      3.Promise.prototype.catch方法:(onRejected) => {}
        onRejected函数:失败的回调函数 reason => {}
        说明:then()的语法糖,箱单和与then(undefined, onRejected)
      4.Promise.resolve方法:value => {}
        value:成功的数据活promise对象
        说明:返回一个成功/失败的promise对象
      5.Promise.reject方法:reason => {}
        reason:失败的原因
        说明:返回一个失败的promise对象
      6.Promise.all方法: promises => {}
        promises: 包含n个promise的数组
        说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败
      7.Promise.race方法: promises => {}
        promises: 包含n个promise的数组
        说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态
    */

    new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('成功的数据');
        // reject('失败的数据');
      }, 1000);
    }).then(
      value => {
        console.log('onResolved()1', value);
      }
    ).catch(
      reason => {
        console.log('onRejected()1', reason);
      }
    )

   // 产生一个成功值为1的peomise对象
   const p1 = new Promise((resolve, reject) => {
    resolve(1);
   })
   const p2 = Promise.resolve(2);
   const p3 = Promise.reject(3);
   p1.then(value => {console.log(value)});
   p2.then(value => {console.log(value)});
   p3.catch(reason => {console.log(reason)});
   // p3的失败也可以这样写
   p3.then(null, reason => {console.log(reason)});

  //  6.Promise.all方法
   const pAll = Promise.all([p1, p2, p3]); // 数组的先后顺序决定了promise的执行顺序(前提是promise都没有做过延迟操作)
   pAll.then(
     values => {
      console.log('all onResolved()', values);
     },
     reason => {
      console.log('all onRejected()', reason);
     }
   )

  //  7.Promise.race方法
   const pRace = Promise.rece([p1, p2, p3]);
   pRace.then(
    value => {
      console.log('race onResolved()', value);
     },
     reason => {
      console.log('race onRejected()', reason);
     }
   )
  </script>
2.3.2 Promise的几个关键问题

1.如何改变promise的状态?
(1)resolve(value):如果当前是pending就会变成resolved
(2)reject(reason):如果当前是pending就会变成rejected
(3)抛出异常:如果当前是pending就会变成rejected
2.一个promise指定多个成功/失败回调函数,都会调用嘛?
当promise改变为对应状态时都会调用

<script>
    /*
      1.如何改变promise的状态?
       (1)resolve(value):如果当前是pending就会变成resolved
       (2)reject(reason):如果当前是pending就会变成rejected
       (3)抛出异常:如果当前是pending就会变成rejected
      2.一个promise指定多个成功/失败回调函数,都会调用嘛?
        当promise改变为对应状态时都会调用
    */
   const p = new Promise((resolve, reject) => {
    // resolve(1); //promise变为resolved成功状态
    // reject(2); // promise变成rejected失败状态
    // throw new Error('出错了'); // 抛出异常,promise变为rejected失败状态,reason为抛出的error
    throw 3; // 抛出异常,promise变为rejected失败状态,reason为抛出的3
   })
   p.then(
     value => {},
     reason => {
       console.log('reason', reason);
     }
   )
   p.then(
     value => {},
     reason => {
       console.log('reason2', reason);
     }
   )
  </script>

第三章 自定义(手写)Promise

第四章 async/await

4.1 async函数

1.函数的返回值为promise对象;
2.promise对象的结果由async函数执行的返回值决定。

4.2 await表达式

1.await右侧的表达式一般为promise对象,但也可以是其他值;
2.如果表达式为peomise对象,await返回的是promise成功的值;
3.如果表达式是其他值,直接将此值作为await的返回值。

4.3 注意

1.await必须写在async函数中,但async函数中可以没有await;
2.如果await的promise失败了,就会抛出异常,需要通过try catch来捕获处理。

4.4 代码演示

<script>
    /*
      1.async 函数
        函数的返回值为promise对象
        promise对象的结果由async函数执行的返回值决定
      2.await 表达式
        await右侧的表达式一般为promise对象,但也可以是其他值
        如果表达式为peomise对象,await返回的是promise成功的值
        如果表达式是其他值,直接将此值作为await的返回值
      3.注意:
        await必须写在async函数中,但async函数中可以没有await
        如果await的promise失败了,就会抛出异常,需要通过try catch来捕获处理
    */

    // async函数的返回值是一个promise对象
    // async函数返回的promise的结果由函数执行的结果决定
    async function fn1() {
      // return 1;
      // throw 2;
      // return Promise.reject(2);
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(4);
        }, 1000);
      });
    }

    const result = fn1();
    // console.log(result);
    result.then(
      value => {
        console.log('onResolved()', value);
      },
      reason => {
        console.log('onRejetced()', reason);
      }
    );

    function fn2() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          // resolve(5);
          reject(6);
        }, 1000);
      });
    }

    async function fn3() {
      try {
        const value = await fn2(); // await右侧表达式为promise,得到的结果为promise成功的结果(await只能得到成功的结果,要想得到失败的结果,得用try catch)
      } catch (error) {
        console.log('得到失败的结果', error);
      }
      // const value = await 3; // await右侧不是promise,得到的结果就是表达式本身
      // console.log('value', value);
    }
    fn3();
  </script>

第五章 JS异步之宏队列与微队列

5.1 原理图

在这里插入图片描述

5.2 说明

1.JS中用来存储待执行回调函数的队列包含2个不同特定的队列。
2.宏队列:用来保存待执行的宏任务(回调),比如:定时器回调、DOM事件回调、ajax回调;
3.微队列:用来保存待执行的微任务(回调),比如:promise的回调、MutationObserver的回调。
4.JS执行时会区别这2个队列
	(1)JS引擎首先必须先执行所有的初始化的同步任务代码;
	(2)每次准备取出第一个宏任务执行前,都要讲所有的微任务一个一个取出来执行。

第六章 promise相关面试题

6.1 面试题1

<script>
    setTimeout(() => {
      console.log(1);
    }, 0);
    Promise.resolve().then(
      () => {
        console.log(2);
      }
    );
    Promise.resolve().then(
      () => {
        console.log(4);
      }
    );
    console.log(3);
    // 打印的结果为:
    // 3
    // 2
    // 4
    // 1
  </script>

6.2 面试题2

<script>
    setTimeout(() => {
      console.log(1);
    }, 0);
    new Promise((resolve, reject) => {
      console.log(2); // 可看02,promise的excutor为同步回调函数
      resolve();
    }).then(
      () => {
        console.log(3);
      }
    ).then(
      () => {
        console.log(4);
      }
    );
    console.log(5);
    // 打印的结果为:
    // 2
    // 5
    // 3
    // 4
    // 1
  </script>

6.3 面试题3

视频链接:

Promise从入门到自定义(promise前端进阶必学)

<script>
    setTimeout(() => {
      console.log(1);
    }, 0);
    new Promise((resolve, reject) => {
      console.log(2); // 可看02,promise的excutor为同步回调函数
      resolve();
    }).then(
      () => {
        console.log(3);
      }
    ).then(
      () => {
        console.log(4);
      }
    );
    console.log(5);
    // 打印的结果为:
    // 2
    // 5
    // 3
    // 4
    // 1
  </script>

6.4 面试题4

视频链接:

Promise从入门到自定义(promise前端进阶必学)

<script>
    // 同步:1 7
    // 宏:[0]
    // 微: [2 8 4 6 5]
    setTimeout(() => {
      console.log('0');
    }, 0);
    new Promise((resolve, reject) => {
      console.log('1');
      resolve();
    }).then(() => {
        console.log('2');
        new Promise((resolve, reject) => {
          console.log('3');
          resolve();
        }).then(() => {
            console.log('4');
          }).then(() => {
            console.log('5');
          });
      }).then(() => {
        console.log('6');
      });

      new Promise((resolve, reject) => {
        console.log('7');
        resolve();
      }).then(() => {
        console.log('8');
      });
      // 打印的结果为:1 7 2 3 8 4 6 5 0
  </script>

附录

相关代码已上传至本人下载页面Promise处,可自行下载查看。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值