Promise学习笔记

Posted 做个机灵鬼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Promise学习笔记相关的知识,希望对你有一定的参考价值。

Promise是什么?

1.抽象表达:

Promise是JS中进行异步编程的新方案(旧的是谁?)

2.具体表达:

(1)从语法上来说: Promise是一个构造函数
(2)从功能上来说: Promise对象用来封装一个异步操作并可以获取其结果

promise实例对象的状态改变

1.pending变为fulfilled
2.pending变为rejected
说明: 只有这2种, 且一个promise对象只能改变一次,无论变为成功还是失败, 都会有一个结果数据, 成功的结果数据一般称为vlaue, 失败的结果数据一般称为reason

为什么要用Promise

支持链式调用, 可以解决回调地狱问题
1.什么是回调地狱?
回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件
2.回调地狱的缺点?
不便于阅读
不便于异常处理
3.一个不是很优秀的解决方案?
promise链式调用
4.终极解决方案?
async/await

API

1.Promise构造函数: Promise (excutor)
(1)excutor函数: 执行器 (resolve, reject) =>
(2)resolve函数: 内部定义成功时我们调用的函数 value =>
(3)reject函数: 内部定义失败时我们调用的函数 reason =>
说明: excutor会在Promise内部立即同步回调,异步操作其中执行

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

3.Promise.prototype.catch方法: (onRejected) =>
(1)onRejected函数: 失败的回调函数 (reason) =>
说明: then()的语法糖, 相当于: then(undefined, onRejected)

4.Promise.resolve方法: (value) =>
(1)value: 成功的数据或promise对象
说明: 返回一个成功/失败的promise对象

5.Promise.reject方法: (reason) =>
(1)reason: 失败的原因
说明: 返回一个失败的promise对象

6.Promise.all方法: (promises) =>
(1)promises: 包含n个promise的数组
说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败

7.Promise.race方法: (promises) =>
(1)promises: 包含n个promise的数组
说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态

改变promise状态和指定回调函数谁先谁后?

(1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
(2)如何先改状态再指定回调?
①在执行器中直接调用resolve()/reject()
②延迟更长时间才调用then()
(3)什么时候才能得到数据?
①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据

promise.then()返回的新promise的结果状态由什么决定?

(1)简单表达: 由then()指定的回调函数执行的结果决定
①如果抛出异常, 新promise变为rejected, reason为抛出的异常
②如果返回的是非promise的任意值, 新promise变为fulfilled, value为返回的值
③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果

 <script type="text/javascript" >
        //  Promise的的then()方法返回的是一个【新的的Promise实例对象】
        /*
        这个新的promise实例对象 它的值和状态由什么决定
        简单的说:由then所指定的回调函数的执行结果决定 
        详细的说:
             1.如果then所指定的回调函数执行的结果为非Promise值 a
                  那么【新的的Promise实例对象】的状态为 :成功fulfilled,成功的值为a
             2.如果then所指定的回调函数执行的结果是实例Promise对象p
                  那么【新的的Promise实例对象】的状态和值都与p一致
             3.如果then所指定的回调抛出异常
                  那么【新的的Promise实例对象】状态为reject err的原因为抛出的那个异常
         */
          const p = new Promise((resolve,reject)=>
              setTimeout(()=>
                 resolve(100)
              ,1000)
          )
           p.then(
               //value这个回调 如果没有指定返回值 全局会帮自动返回一个undefind
               value => console.log('成功了1',value); return 900,
               reason => console.log('失败了1',reason);
           ).then(
               value => console.log('成功了2',value); return Promise.resolve(800),
               reason => console.log('失败了2',reason);
           ).then(
            //    如果返回一个失败的promise实例 那么将会走失败的回调
               value => console.log('成功了3',value); return Promise.reject(700),
               reason => console.log('失败了3',reason);
           ).then(
               value => console.log('成功了4',value);,
               reason => console.log('失败了4'); return 600
           ).then(
               value => console.log('成功了5',value); throw 500,
               reason => console.log('失败了5');
           ).then(
               value => ,
               reason => console.log('失败了6',reason);
           )
        </script>

promise异常传透?

(1)当使用promise的then链式调用时, 可以在最后指定失败的回调,
(2)前面任何操作出了异常, 都会传到最后失败的回调中处理

 <script type="text/javascript">
      // promise错误穿透
      /* 
         promise的then()方法链式调用的时候,不用每个then方法里面都写失败的回调
         只需要写在最后一个catch()函数
        */
      function sendAjax(url, data) 
        return new Promise((resolve, reject) => 
          const xhr = new XMLHttpRequest();
          //绑定监听
          xhr.onreadystatechange = () => 
            if (xhr.readyState === 4) 
              if (xhr.status >= 200 && xhr.status < 300) 
                resolve(xhr.response);
               else reject("失败了");
            
          ;
          let str = "";
          for (key in data) 
            str += `$key=$data[key]&`;
          
          str.slice(0, -1);
          xhr.open("GET", url + "?" + str);
          xhr.responseType = "json";
          xhr.send();
        );
      

      sendAjax("https://api.apiopen.top/getJoke",  name: "小刘", age: "18" )
        .then(
          (value) => 
            console.log("成功了1", value);
            return sendAjax("https://api.apiopen.top/getJoke2", 
              name: "小刘",
              age: "18",
            );
          ,
          //   reason => console.log('失败了1'); return new Promise(()=>)
          //错误穿透底层原理 每一个then方法自动帮补了一个抛出异常
          //那么then返回的为一个失败promise的对象
          (reason) => 
            throw Error;
          
        )
        .then(
          (value) => 
            console.log("成功了2", value);
            return sendAjax("https://api.apiopen.top/getJoke", name: "小刘",age: "18",
            );
          
          //   reason => console.log('失败了2');
        )
        .then(
          (value) => console.log("成功了3", value);
          //   reason => console.log('失败了3');
        )
        .catch((reason) => 
          console.log("出错了");
        );
    </script>

async 函数

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

await 表达式

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

注意

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

<script type="text/javascript" >
         //async和await的使用
         const p1 = new Promise((resolve,reject)=>
            setTimeout(()=>
               resolve('a');
            ,1000)
         );
         const p2 = new Promise((resolve,reject)=>
            setTimeout(()=>
                reject('一些错误');
            ,2000)
         );
         const p3 = new Promise((resolve,reject)=>
            setTimeout(()=>
               resolve('c');
            ,3000)
         );

         ;( async()=>
                try 
                //await可以等待成功的promise实例对象的返回值
                 const result1 = await p1;
                 console.log(result1);
                 const result2 = await p2;
                 console.log(result2);
                 const result3 = await p3;
                 console.log(result3);
                 catch (error) 
                    console.log(error);
                
             
         )()
        </script>

宏队列和微队列

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

下面来看一道面试题

 <script type="text/javascript" >
        // 宏队列和微队列
        setTimeout(()=>
          console.log('setTimeout1');
          //在执行这个回调时,输出setTimeout1 再把then方法的回调放入伪队列
          //在执行setTimeout2前 先把这个微任务执行了 因为优先级的
          Promise.resolve(2).then(
               value => console.log('成功了Promise2');
          )
        )
        setTimeout(()=>
          console.log('setTimeout2');
        )
         Promise.resolve(3).then(
            value => console.log('成功了Promise3');
        )
         Promise.resolve(4).then(
            value => console.log('成功了Promise3');
        )
        </script>

以上是关于Promise学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

Promise学习笔记

《Promise学习笔记》- 2Promise相关常用方法总结

Promise/commonJS/AMD学习笔记

es6学习笔记--promise对象

ES6中Promise学习笔记

Promise回调地狱学习小小小小小笔记