ES6-Promise上

一。Promise作用:解决回调地狱问题

transitionend是过渡结束事件,只要过渡结束就会触发;
回调地狱:指的是层层嵌套的回调函数,代码看起来非常晕
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Promise 是什么</title>
    <style>
      * {
        padding: 0;
        margin: 0;
      }

      #box {
        width: 300px;
        height: 300px;
        background-color: red;
        transition: all 0.5s;
      }
    </style>
  </head>
  <body>
    <div id="box"></div>

    <script>
      // 1.认识 Promise
      // Promise 是异步操作的一种解决方案
      // 回调函数
      // document.addEventListener(
      //   'click',
      //   () => {
      //     console.log('这里是异步的');
      //   },
      //   false
      // );
      // console.log('这里是同步的');

      // 2.什么时候使用 Promise
      // Promise 一般用来解决层层嵌套的回调函数(回调地狱 callback hell)的问题
      // 运动
      const move = (el, { x = 0, y = 0 } = {}, end = () => {}) => {
        el.style.transform = `translate3d(${x}px, ${y}px, 0)`;

        el.addEventListener(
          'transitionend',
          () => {
            // console.log('end');
            end();
          },
          false
        );
      };
      const boxEl = document.getElementById('box');

      document.addEventListener(
        'click',
        () => {
          move(boxEl, { x: 150 }, () => {
            move(boxEl, { x: 150, y: 150 }, () => {
              move(boxEl, { y: 150 }, () => {
                // console.log('object');
                move(boxEl, { x: 0, y: 0 });
              });
            });
          });
        },
        false
      );
    </script>
  </body>
</html>

 

 

 

 二。实例Promise,实例的then方法,resolve和reject函数及其参数,Promise三种状态

 

 

第一个参数是成功态,第二个是失败态;

 

 

pending等待状态,箭头函数函数体里面没调用resolve 和 reject 时,只要实例一个Promise就是这个状态,可以理解为初始状态

 

 

 

当我们执行resolve方法后,变成成功状态 pending---fulfilled

 

 

 

当我们执行reject方法后,变成失败状态 pending---rejected

 

 

 注意:只要promise回调函数这个实参函数体里面写了resolve()或者reject(),都可以改变状态;

        const p = new Promise(function (resolve, reject) {

            function fn() {
                resolve()//这个位置(写在其他函数体里)写了resolve()也能将p的状态转换成成功态
            };
            fn();
        });
        console.log(p);//Promise {<fulfilled>: undefined}

 

 

 如果resolve 和 reject 都在箭头函数里调用:没有成功<--->失败态之间的转变,只有初始-->成功或者初始-->失败;

 

 Promise实例都有then方法(其实是构造函数.prototype的方法--实例可以访问原型的方法属性),p调用then方法p本身不会变

 

 

 

 可以理解then方法内部判断p的状态,然后再内部决定调用哪个回调函数;

resolve 和 reject 方法的参数:reject 方法同理

 

 

 

 

 

 请问三种状态指的是实例的还是构造函数的,应该指的是实例的吧?-----对!

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Promise 的基本用法</title>
  </head>
  <body>
    <script>
      // 1.实例化构造函数生成实例对象
      // console.log(Promise);

      // Promise 解决的不是回调函数,而是回调地狱
      // const p = new Promise(() => {});

      // 2.Promise 的状态
      // const p = new Promise((resolve, reject) => {
      //   // Promise 有 3 种状态,一开始是 pending(未完成),执行 resolve,变成 fulfilled(resolved),已成功
      //   // 执行 reject,变成 rejected,已失败

      //   // Promise 的状态一旦变化,就不会再改变了

      //   // pending->fulfilled
      //   // resolve();

      //   // pending->rejected
      //   reject();
      // });

      // 3.then 方法
      // p.then(
      //   () => {
      //     console.log('success');
      //   },
      //   () => {
      //     console.log('error');
      //   }
      // );

      // 4.resolve 和 reject 函数的参数
      const p = new Promise((resolve, reject) => {
        // Promise 有 3 种状态,一开始是 pending(未完成),执行 resolve,变成 fulfilled(resolved),已成功
        // 执行 reject,变成 rejected,已失败

        // Promise 的状态一旦变化,就不会再改变了

        // pending->fulfilled
        // resolve('succ');
        // resolve({ username: 'alex' });

        // pending->rejected
        // reject('reason');
        reject(new Error('reason'));
      });
      p.then(
        data => {
          console.log('success', data);
        },
        err => {
          console.log('error', err);
        }
      );

      console.log(p);
    </script>
  </body>
</html>

 三。实例的then方法

 

 

 

执行第一个回调函数

 

 

 then方法内部调用哪个回调函数(then方法的两个实参)取决于调用then方法的promise实例他的状态

 

 then里面回调函数的返回值就是Promise实例调用then方法的返回值;

 

 

then里面的异步:(挂起)

then里面的回调是异步,所以先执行打印p2;

未展开之前的状态才是执行console.log(p2)语句输出p2时的结果,即pending状态(虽然p2还没完成彻底赋值,里面的回调是异步,但是打印p2已经是promise实例了,只不过是pending状态

展开后查看的是p2最终的结果,也就是说p2最终是会变成fulfilled状态,但是由于代码是异步执行的,所以在执行console.log(p2)输出时p2的状态为pending状态

假如程序执行时调用then的实例是pending,那这段调用then的代码会挂起,继续执行接下来要执行的同步异步等代码(挂起目的就是等待实例状态变化再来调用then,就是回头又执行),等这个实例状态变化了就会马上执行then(挂起状态结束),不论then里面的回调是否执行,这段代码不会再回头执行了;  

注意,如果程序执行时,实例打点调用then,这个实例的状态确定,就不存在挂起这回事了;都是直接执行then或者跳过(比如成功态调用catch),不存在回头了

下图,程序执行p1.then时,p1此时虽然赋值还没结束,但是已经是promise实例了,只不过是pending状态

 

 

注意:return后面不是promise实例时,直接写个return 数据,不写return也是return undefined ,就相当于return new Promise(function(resolve,reject){

resolve(数据)

});------------------这就是默认用promise包装一下

且默认都是调用resolve(),所以then方法返回的是成功状态的promise实例;

return后面是promise实例时,就不会包装了;

 

 

 

      // 1.什么时候执行
      // pending->fulfilled 时,执行 then 的第一个回调函数
      // pending->rejected 时,执行 then 的第二个回调函数

      // 2.执行后的返回值
      // then 方法执行后返回一个新的 Promise 对象
      // const p = new Promise((resolve, reject) => {
      //   resolve();
      //   // reject();
      // });
      // const p2 = p
      //   .then(
      //     () => {},
      //     () => {}
      //   )
      //   .then()
      //   .then();

      // console.log(p, p2, p === p2);

      // 3.then 方法返回的 Promise 对象的状态改变
      // const p = new Promise((resolve, reject) => {
      //   // resolve();
      //   reject();
      // });
      // p.then(
      //   () => {
      //     // console.log('success');
      //   },
      //   () => {
      //     console.log('err');

      //     // 在 then 的回调函数中,return 后面的东西,会用 Promise 包装一下
      //     // return undefined;
      //     // 等价于
      //     // return new Promise(resolve => {
      //     //   resolve(undefined);
      //     // });

      //     return 123;
      //     // return new Promise(resolve => {
      //     //   resolve(123);
      //     // });

      //     // 默认返回的永远都是成功状态的 Promise 对象
      //     // return new Promise((resolve, reject) => {
      //     //   reject('reason');
      //     // });
      //   }
      // )
      //   .then(
      //     data => {
      //       console.log('success2', data);

      //       // return undefined;
      //       return new Promise(resolve => {
      //         resolve(undefined);
      //       });
      //     },
      //     err => {
      //       console.log('err2', err);
      //     }
      //   )
      //   .then(
      //     data => {
      //       console.log('success3', data);
      //     },
      //     err => {
      //       console.log('err3', err);
      //     }
      //   );

 注意点:调用then方法的返回值只跟then方法实参(两个回调函数)return后面的东西有关,当然我们要看看这两个回调哪个执行,不执行有return也没用;

调用then方法的返回值,我们主要关注两个:返回值promise实例的状态以及其以promise包装时resolve 或者reject 的参数;状态决定其调用then方法时then的哪个回调执行,参数的话,then的回调形参接收promise包装时resolve 或者reject 的参数;

如果连续打点调用then方法,就按照如下思路分析,不容易乱:

 

 

 

注意点:Promise构造器里面的回调函数里面的形参的顺序 :第一个一定是成功态,第二个一定是失败态,虽然不一定要写全形参

then里面的回调函数也是要注意顺序:第一个参数(回调函数)一定是Promise实例为成功态时被then内部调用,第二个参数(回调函数)一定是Promise实例为失败态时被then内部调用,虽然不一定要写全这两个回调函数;

四。解决回调地狱问题

 

 

 重点:每一次调用movePromise会返回新的成功态p,且盒子本次达到目标位置

<!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>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        #box {
            width: 300px;
            height: 300px;
            background-color: red;
            transition: all 0.5s;
        }
    </style>
</head>

<body>
    <div id="box"></div>
    <script>
        const box = document.getElementById('box')
        const move = function (el, { x = 0, y = 0 } = {}, end = function () { }) {
            el.style.transform = `translate3d(${x}px,${y}px,0)`;
            el.addEventListener(
                'transitionend',
                function () {
                    end();
                }
            );
        };
        const movePromise = function (el, point) {//只要调用movePromise(),那么就会调用move(),过渡做完resolve执行,promise实例状态转化成成功,再打点调用then方法里面的回调才会执行
            return new Promise(function (resolve, reject) {
                move(el, point, function () {//promise里面的回调函数一定会被执行
                    resolve();
                });
            });



        };
        document.addEventListener('click', function () {
            movePromise(box, { x: 100 }).then(function () {
                return movePromise(box, { x: 100, y: 100 })
            }).then(function () {
                return movePromise(box, { x: 0, y: 100 })
            }).then(function () {
                return movePromise(box, { x: 0, y: 0 })
            })



        })


        //只要调用一次movePromise 就会返回一个新的promise实例,且这个新实例p生成的过程中会调用move(),过渡做完resolve执行,该promise实例状态转化成成功,此时调用movePromise 完毕,再打点调用then方法,then里面的回调执行

       
        // document.addEventListener('click', function () {
        //     move(box, { x: 100 }, function () {
        //         move(box, { x: 100, y: 100 }, function () {
        //             move(box, { x: 0, y: 100 }, function () {
        //                 move(box, { x: 0, y: 0 });
        //             });
        //         });
        //     });
        // })

    </script>
</body>

</html>

 

以下是个人更深入的理解:(挂起)

 

 如果then中不写return,那么就相当于调用moveP后再return undefined,因为调用moveP会有过渡运动开始运动,与此同时return undefined执行,第一个实例p.then()的返回值就是默认的成功态新p马上确定了,这个p马上接着调用then方法,马上执行then的回调函数,调用moveP后再return undefined(注意此时前面then中的过度运动还没执行完毕),下一个then的移动逻辑会覆盖上一个then的效果,就会导致bug的出现。

 五。实例的catch方法

 

 

相当于then(null,function(err){} )

 

直接跳过当不存在;

 

 

 

虽然会一直跳过往后找,失败态的实例连续一次或者多次打点调用时如果后面的then方法(catch也算是then)如果一直没有出现第二个参数,是会报错的

错误的意思就是说有个失败态的实例调用then方法一直都是无效

捕获错误就是让这个失败态实例成功调用一次then方法,让then里面的回调函数可以执行

 

错误提示:没有被捕获的错误;因为第一个实例是失败态,如果后面的then方法一直没有出现第二个参数(没有处理错误),是会报错的

 

但是成功态的实例调用then方法失效是不会报错的(then方法第一个参数为null),即使后面连续打点调用then都失效(then方法第一个参数为null),也不会报错,

 

 

跳过时的参数传递

 

 

 catch方法直接看作是then方法的特例即可,一样会返回新的promise实例,和then一模一样;

前面我们想调用then方法返回一个失败态的实例,就得手动添加return new Promise(resolve,reject){reject()},在catch方法里可以使用throw,就相当于return new Promise(resolve,reject){reject(throw后面的数据)};

不仅在catch方法里。then方法也可以写throw,和catch里面用法一样

 

 

 成功态实例调用then方法,如果then第一个参数为null,不会报错;如果连续打点调用then时,遇到的都是这样的then也一样不会报错,规则是遇到then第一个参数为null就直接跳过去调用下一个then

失败态实例调用then方法,then参数只有一个回调函数会报错;如果连续打点调用then时,如果所有的then都失效,会报错,如果有一个then执行了回调,那么该错误被捕获,也获得了返回值实例,如果后面接着调用then要看看返回值实例的状态,如果是失败态就得接着注意该步骤;

 不论成功还是失败态,遇到失效都会跳过往下找只不过成功态找不到能执行回调的then不会报错,失败态会报错;

注意,报错不会影响后续代码的执行;

关于报错我的理解:

程序只要监测到调用了reject(),就会抛出异常,假如这个promise实例过程中调用了reject(),只要这个失败态实例打点调用then方法(例如catch)且成功执行了里面的回调函数(并没有跳过这个then),那么这个异常就消失,如果其调用then方法返回值又是一个失败态实例(返回值在实例过程中又调用了reject()),那么又会抛出异常,直到这个返回值失败态实例打点调用then方法(例如catch)且成功执行了里面的回调函数,那么这个异常就消失;

注意:捕获错误可以用then也可以用catch,catch只是特殊的then而已;

posted @ 2023-01-20 19:44  游千山  阅读(31)  评论(0)    收藏  举报