Promise教程(二)

Promise教程(二)

第三章:Promise的优势

then的链式调用

Promise实例.then()返回的是一个【新的Promise实例】,它的值和状态由什么决定?

  1. 简单表达:由then()所指定的回调函数执行的结果决定

  2. 详细表达:

    1. 如果then所指定的回调返回的是非Promise值a,那么【新Promise实例】状态为:成功(fulfilled),成功的value为a
    2. 如果then所指定的回调返回的是一个Promise实例p,那么【新Promise实例】的状态、值,都与p一致
    3. 如果then所指定的回调抛出异常,那么【新Promise实例】状态为rejected,reason为抛出的那个异常
    const p = new Promise((resolve,reject) => {
        setTimeout(() => {
            resolve(100)
        },1000)
    })
    p.then(
        (value) => {console.log('sucess1',value); return Promise.reject('a')},
        (reason) => {console.log('err1',reason)}
    ).then(
        (value) => {console.log('sucess2',value); return true},
        (reason) => {console.log('error2',reason); return 100}
    ).then(
        (value) => {console.log('sucess3',value); return false},
        (reason) => {console.log('error3',reason); return false}
    ).then(
        (value) => {console.log('sucess4',value); return -100},
        (reason) => {console.log('error4',reason);}
    )
    
纯回调会引起的问题(回调地狱)
  1. 什么是回调地狱

    函数作为参数层层嵌套,回调函数嵌套调用,,外部回调函数异步执行的结果是嵌套的回调函数执行的条件

  2. 回调地狱的原因是

    回调地狱是由于糟糕的编码习惯造成的,功能逻辑代码嵌套的层次太多,导致可读性降低,维护困难,避免回调地狱的最重要的方面是将功能移开,保持代码简单,不嵌套并分成小模块,也就是多多进行代码封装

  3. 如何解决回调地狱

    Promise的出现就是解决Node.js异步编程中回调地狱的问题

    then的链式调用解决回调地狱(不是很优秀的解决方案)

    //发送第一次请求
    sendAjax('https://www.tianqiapi.com/free/day',{appid:23035354,appsecret:'8YvlPNrz'})
    .then(
        value => {
            console.log('第一次请求成功',value)
            return sendAjax('https://www.tianqiapi.com/free/day',{appid:23035354,appsecret:'8YvlPNrz'})
        },
        reason => {console.log('第一次请求失败',reason)}
    )
    .then(
        value => {
            console.log('第二次请求成功',value)
            return sendAjax('https://www.tianqiapi.com/free/day',{appid:23035354,appsecret:'8YvlPNrz'})
        },
        reason => {console.log('第二次请求失败',reason)}
    )
    .then(
        value => {
            console.log('第三次请求成功',value)
        },
        reason => {console.log('第三次请求失败',reason)}
    )
    
中断promise链:
  1. 当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数

  2. 办法:在失败的回调函数中返回一个pending状态的Promise实例

    //发送第1次请求
    sendAjax('https://api.apiopen.top/getJoke',{page:1})
        .then(
        value => {
            console.log('第1次请求成功了',value);
            //发送第2次请求
            return sendAjax('https://api.apiopen.top/getJoke2',{page:1})
        },
        reason => {console.log('第1次请求失败了',reason);return new Promise(()=>{})}
    )
        .then(
        value => {
            console.log('第2次请求成功了',value);
            //发送第3次请求
            return sendAjax('https://api.apiopen.top/getJoke',{page:1})
        },
        reason => {console.log('第2次请求失败了',reason);return new Promise(()=>{})}
    )
        .then(
        value => {console.log('第3次请求成功了',value);},
        reason => {console.log('第3次请求失败了',reason);}
    )
    
promise错误穿透
  1. 当使用promise的then链式调用时,可以在最后用catch指定一个失败的回调

  2. 前面任何操作出了错误,都会传到最后失败的回调中处理

    备注:如果不存在then的链式调用,就不需要考虑then的错误穿透

    //利用错误的穿透避免多次指定失败的回调
    sendAjax('https://api.apiopen.top/getJoke2',{page:1})
    .then(
        value => {
            console.log('第1次请求成功了',value);
            //发送第2次请求
            return sendAjax('https://api.apiopen.top/getJoke',{page:1})
        }
    )
    .then(
        value => {
            console.log('第2次请求成功了',value);
            //发送第3次请求
            return sendAjax('https://api.apiopen.top/getJoke',{page:1},3)
        }
    )
    .then(
        value => {console.log('第3次请求成功了',value);}
    )
    .catch(
        reason => {console.log(reason);}
    )
    
Promise的优势
  1. 指定回调函数的方式更加灵活:
    1. 旧的: 必须在启动异步任务前指定
    2. promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定)
  2. 支持链式调用, 可以解决回调地狱问题
    1. 一个不是很优秀的解决方案:then的链式调用
    2. 终极解决方案:async/await(底层实际上依然使用then的链式调用)

第4章:async和await

async和await的使用
  1. async修饰的函数

    1. 函数的返回值为Promise对象
    2. Promise实例的结果由async函数执行的返回值决定
  2. await表达式

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

    1. await必须写在async函数中,但async函数中可以没有await
    2. 如果await的Promise实例对象失败了,就会抛出异常,需要通过try…catch来捕获处理
    const p = new Promise((resolve,reject) => {
        setTimeout(() => {
            resolve(1)
        },1000)
    })
    ;(async () => {
        try{
            const result = await p
            console.log(result)
        }catch(e){
            //TODO handle the exception
            console.log(e)
        }
    })()
    
await的原理
  • 若我们使用async配合await这种写法:

    • 表面上不出现任何的回调函数
    • 但实际上底层把我们写的代码进行了加工,把回调函数“还原”回来了
    • 最终运行的代码是依然有回调的,只是程序员没有看见
    const p = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve('a')
        },4000)
    })
    
    async function demo(){
        //程序员“轻松”的写法
        const result = await p
        console.log(result);
        console.log(100);
        console.log(200);	
        //浏览器翻译后的代码
        /* p.then(
    		result => {
    			console.log(result);
    			console.log(100);
    			console.log(200);
    		},
    	) */
    
    }
    demo()
    console.log(1);
    
宏队列与微队列
  1. 宏队列:[宏任务1,宏任务2…]
  2. 微队列:[微任务1,微任务2…]
  3. 规则:每次要执行宏队列里的一个任务之前,先看微队列里是否有待执行的微任务
    1. 如果有,先执行微任务
    2. 如果没有,按照宏队列里任务的顺序,依次执行
  //代码一
  setTimeout(()=>{
    console.log('timeout')
  },0)

  Promise.resolve(1).then(
    value => console.log('成功1',value)
  )
  Promise.resolve(2).then(
    value => console.log('成功2',value)
  )
  console.log('主线程')
  //代码二
  setTimeout(()=>{
    console.log('timeout1')
  })
  setTimeout(()=>{
    console.log('timeout2')
  })

  Promise.resolve(1).then(
    value => console.log('成功1',value)
  )
  Promise.resolve(2).then(
    value => console.log('成功2',value)
  )

  //代码三
  setTimeout(()=>{
    console.log('timeout1')
    Promise.resolve(5).then(
      value => console.log('成功了5')
    )
  })
  setTimeout(()=>{
    console.log('timeout2')
  })

  Promise.resolve(3).then(
    value => console.log('成功了3')
  )
  Promise.resolve(4).then(
    value => console.log('成功了4')
  )
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值