js高阶——Promise学习

 

目录

基本概念

回调函数:

Pomise是什么?

Promise和纯回调函数对比:

Promise的API:

Promise的注意点:

1.改变promise状态的三种方式

2.如果给同一个promise指定多个成功/失败的回调函数,都调用吗?

3.改变promise状态和指定回调函数的顺序?

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

5.promise如何串连多个操作任务?

6.promise异常传透?

7.如何中断promise链?

async 和 await

1.async函数

2.await 表达式

3.注意:

宏队列和微队列


基本概念

实例对象:通过new 函数产生的对象

函数对象:将函数作为对象使用时,叫函数对象。

function Fn(){   //构造函数

}

const fn = new Fn() // fn——实例对象
console.log(Fn.protoype) // 通过.来访问函数Fn的属性,此时Fn是函数对象
Fn.call({})   // Fn是函数对象,所有函数对象都有这个call()属性,所以call其实定义在Function.prototype上

 


回调函数:

1.同步回调: 立即执行,完全执行完成才结束,不放入回调队列中

    eg:数组遍历的回调函数map/filter/reduce等 / Promise的excutor函数

2.异步回调:不会立即执行,而是放进回调队列中

    eg:setTimeout(()=>{},s) 里面的回调函数

 


Pomise是什么?

 

1.理解: Promise是Js中进行异步编程的的新的解决方案(旧的是指纯回调函数形式,容易产生回调地狱)

2.具体: 

  • 从语法上来说:Promise就是一个构造函数

  • 从功能上来说:promise对象用来封装一个异步操作,还能获取这个操作的结果。

3.promise的状态改变:一个promise对象只能改变一次

  • pending ——> resolved

  • pending ——> rejected

Promise基本使用:

// 1.创建一个新的promise对象
const p = new Promise((resolve,reject)=>{  //执行器函数
    // 2.执行异步任务
    setTimeout(()=>{
        const time = Date.now();
          // 3.1 如果成功,调用resolve(value)
        if (time %2 == 0){
            resolve('成功'+time)
        }else {   // 3.2 如果失败,调用reject(reason)
            reject('失败'+time)
        }
    },1000)
  
    
})

p.then(
    value => {  //接收得到的成功的value数据   onResolved
        console.log('成功的回调',value)
    },
    reason =>{ // 接收得到的失败的reason数据   onRejected
        console.log('失败的回调',reason)
    }
)

Promise和纯回调函数对比:

纯回调函数: 需要先指定好回调函数,再调用回调函数来执行异步任务

Promise:可以先启动异步任务,(即在执行器函数中启动异步任务(即加入任务队列之中,因为执行器函数是同步回调,在new Promise的时候就执行) ),甚至可以在 异步任务执行完成之后再指定回调函数。

所以Promise的优势: 

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

    • 旧的:必须在启动异步任务之前指定好

    • promise:启动异步任务—>返回promise对象—>给promise对象绑定回调函数(甚至可以在异步任务结束后) 

  2. 支持链式调用,可以解决回调地狱问题

    • 什么是回调地狱? 回调函数嵌套使用,外部回调函数异步执行的结果是嵌套的回调函数执行的条件

    • 回调地狱的缺点? 不便于阅读,不便于异常处理

    • 解决方案? promise链式调用 ——>async/await


Promise的API:

1.Promise构造函数:Promise(excutor) {}

excutor函数:同步执行: (resolve,reject )=>{}

resolve函数:excutor函数中成功时调用的函数 : value=>{ }

reject函数:excutor函数中失败时调用的函数:reason=>{ }

excutor 在promise中立即同步执行,异步操作封装在excutor函数中执行

2.Pomise.prototype.then()方法:(onResolved,onRejected)=>{ }

onResolved函数:成功的回调函数

onRejected函数:失败的回调函数

用于指定成功或者失败的回调函数,返回一个新的promise对象

 

3.Promise.prototype.catch() 方法:(onRejected) =>{ }

用于指定失败的回调函数,相当于 then(null,onRejected)

 

4.Promise.resolve()方法 :(value) => { }

value:成功的数据或者是一个promise对象

返回的是一个成功或者失败的promise对象

 

5.Promise.reject()方法

// 产生一个成功值为1的promise对象
const p1 = new Promise((resolve,reject)=>{
    resolve(1)
})

// 语法糖 
const p2 = Promise.resolve(1)

6.Promise.all() 方法:(promises) =>{ }

promises:包含n个promise的数组

返回一个新的promise,只有所有的promise都成功才算成功,有一个失败就失败了

 

7.Promise.race()方法: (promises)=>{ }

返回一个新的promise,是第一个完成的promise的结果状态。


Promise的注意点:

1.改变promise状态的三种方式

  1. resolve(value):  pending——>resolved

  2. reject(reason): pending——>rejected

  3. throw 异常:pending——>rejected (reason就是throw出来的Error)

2.如果给同一个promise指定多个成功/失败的回调函数,都调用吗?

    当promise改变状态时都会调用

3.改变promise状态和指定回调函数的顺序?

  1. 顺序不一定,正常来说是应该先指定回调函数再改状态,但是也可以先改状态再指定回调

  2. 如何先改状态再指定回调?

    • 在执行器函数里面直接执行resolve()/reject()

    • 延迟更久的事件才调用then()

  3. 什么时候得到数据?

    • 如果先指定回调函数,那么当状态改变时,就直接调用回调函数,得到数据

    • 如果先改变状态,那么当你指定回调函数时,才调用回调函数,得到数据

// 1.先指定回调函数,后改状态
new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(1);    // 异步执行回调函数  ——后改状态,同时指定数据
    },1000);
}).then(  // 同步指定回调函数,保存当前指定的回调函数   ——先指定回调函数 
    value =>{console.log('value1',value)},
    reason=>{}
)

// 2.先改状态,后指定回调函数(1)
new Promise((resolve,reject)=>{
    resolve(1);    //先改状态,同时指定数据
}).then(  // 后指定回调函数,异步执行回调函数
    value =>{console.log('value2',value)},
    reason=>{}
)

// 3.先改状态,后指定回调函数(2)
const pro = new Promise((resolve,reject)=>{
   setTimeout(()=>{
       resolve(1);
   },1000);
});

setTimeout(()=>{
    pro.then(
        value=>{console.log('value3',value)},
        reason=>{}
    )
},3000)

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

  1. 由then()指定的回调函数的执行结果决定

    1. 如果抛出异常,新的promise状态时rejected,reason就是抛出的err

    2. 如果返回的是一个非promise的值,新的promise就变成resolved,value为这个返回值

    3. 如果返回的是另一个新的promise,那么这个新的promise的结果就是then()返回的promise的结果

5.promise如何串连多个操作任务?

  1. 因为promise的then()返回的是新的promise,可以利用then()来链式调用

  2. 通过then的链式调用串联多个同步/异步任务

// 链式调用
new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(1);
    })
}).then(
    value=>{
        console.log('任务1的结果:',value);
        console.log('执行任务2(同步)');
        return 2;
    }
).then(
    value=>{
        console.log('任务2的结果',value);
        //启动异步任务
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                console.log('执行任务3(异步)');
                resolve(3)
            },1000)
        }).then(
            value=>{
                console.log('任务3的结果',value)
            }
        )
    }
)

6.promise异常传透?

  1. 当promise进行链式调用时,可以在最后指定失败的回调

  2. 当前任何操作出了异常,都会传到最后失败的回调中进行处理

  3. 没有写onRejected函数,相当于 reason=>{throw reason},逐级向下抛,最后找到尾巴处的catch

7.如何中断promise链?

  1. 可以在回调函数中间返回一个pending状态的promise对象

  2. 这样就可以在链式调用的中间中断,不再调用后面的回调函数


async 和 await

1.async函数

  1. 函数的返回值是promise对象

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

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

        const result = fn1();
        result.then(
            value => {console.log('onResloved()',value)},
            reason => {console.log('onRejected()',reason)}
        )

2.await 表达式

  1. await右侧的表达式一般是promise对象,也可以是其他值

  2. 如果表达式是promise对象,那么 await返回的是promise 成功的值

  3. 如果表达式是其他值,那么这个值就是await的返回值


        function fn2(){
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    // resolve(5);
                    reject(7);
                },1000)
            })
        }
        async function fn3(){
            // const value = await fn2();  // await 右侧表达式是promise,得到的结果就是promise成功的value
            // const value = await 6;  // await 右侧表达式是一个其他值,得到的结果就是这个值本身
            try {
                const value = await fn2();
                console.log('value',value);
            }catch (error){
                console.log('失败的结果',error);
            }
        }

        fn3();
        

3.注意:

  1. await必须写在async函数里面,async函数里面可以没有awiat

  2. 如果await的promise失败了,会抛出异常,所以await要写在try…catch里面


宏队列和微队列

执行回调函数的队列分为宏队列和微队列

  1. 宏队列:用来保存待执行的宏任务(回调),定时器回调/DOM事件回调/ajax回调

  2. 微队列:用来保存待执行的微任务(回调),promise回调/mutationObserver回调

  3. 执行顺序:js引擎 先执行所有初始化同步任务, 每次从宏队列取出第一个宏任务执行之前,都要将所有的微任务一个一个取出来执行

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值