浅谈ES6中的Promise和async/await

98 阅读3分钟

Promise

  1. es6推出的新的更好的异步编程解决方案
    • 可以在异步操作启动后或完成后,在指定回调函数得到异步结果数据
    • promise的链式调用可以解决嵌套回调的回调地狱问题
  2. promise对象的三种状态
    1. pengding(初始状态)
    2. fulfilled(成功状态)
    3. rejected(失败状态)
  3. Promise
    1. Promise是一个构造函数,用于创建promise实例对象
    2. Promise构造函数必须接受一个实参,也就是执行器函数,该执行器函数会被同步执行
      • 执行器函数接受2个实参
        1. resolve:可以将当前promise状态改为成功
        2. reject:可以将当前promise状态转为失败
  4. promise.then
    1. 该函数最多接受2个实参,数据类型为函数
      • 如果前面promise状态为成功,触发第一个回调,否则触发第二个
    2. 总是返回一个新的promise
    3. 新的promise的结果由then指定回调的结果决定
  • 扩展
    1. 如何让.than的回调返回成功
      1. 返回值不是promise对象
      2. 返回成功的promise
    2. 如何让.then的回调返回失败
      1. 报错
      2. 返回失败的promise
  1. promise.all([promise1,promise2])
  • 批量发送多个异步请求
  • 全部成功才返回成功的promise
  • 一个失败,就返回失败的promise
  1. promise.race([promise1,promise2])
  • 批量发送多个异步请求,谁先回来用谁

async/await的基本概念

  1. promise的语法糖,简化promise对象的使用,不用再使用then/catch来指定回调
  2. 用同步的方式来执行异步操作的效果
  3. await相当于promise.then
  4. try/catch可捕获异常,相当于promise.catch
  5. await之后的代码都会被放在promise的.then的成功回调中,一定会返回一个全选的promise

async

语法:在函数开头添加async即可

async有什么用?

  • 可以让该函数返回一个promise,如果函数有返回值,async会用Promise.resolve()包裹并返回
async function fn() {
    console.log('async'); // async
    return 'then';
}
fn().then((res) => {
    console.log(res) // then
}) 

await

语法:[返回值] = await 表达式

await操作符用于等待一个Promise对象,只能在异步函数async function中使用

await 会阻塞当前代码的执行,等待 Promise 处理完成

await不能单独使用,会报错

await后跟成功的promise或非promise对象,则返回成功的promise

回调地狱问题

如何实现回调地狱?

  • 多个串联的异步操作就会导致回调地狱 我们可以用定时器去简单的模拟一下回调地狱
// 1秒后打印1,2秒后打印2,3秒后打印3
setTimeout(() => {
    console.log(1);
    setTimeout(() => {
        console.log(2);
        setTimeout(() => {
            console.log(3);
        }, 3000);
    }, 2000);
}, 1000);

可以看到,每多一个异步操作,代码就会向右缩进,代码的可读性会非常差,串联的少还好,串联的多的话,整体就会很混乱

使用Promise去解决回调地狱问题

function log123(){
    return new Promise((resolve,reject)=>{ // 执行器函数,接收2个参数
                                           // resolve 可以将当前promise状态改为成功
                                           // reject 可以将当前promise状态改为失败
        setTimeout(()=>{
            console.log(1)
            resolve(2) // 返回成功的promise并携带参数2
        },1000)
    })
}
log123().then((value)=>{ // value接收参数
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log(value)
            resolve(3) // 返回成功的promise并携带参数3
        },2000)
    })
}).then((value)=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log(value)
            return '时间到!'
        },3000)
    })
}).then((res)=>{
    console.log(res)
})

可以看到,代码不会一直向右缩进,逻辑分明,代码可读性好

使用async/await解决回调地狱问题

var log = function(time){
    return new Promise((resolve,reject)=>{
        return setTimeout(()=>{
            console.log(time/1000) 
            resolve()
        },time)
    })
} 
async function log123(){
    await log(1000)
    await log(2000)
    await log(3000)
    return '时间到!'
}
log123().then((res)=>{
    console.log(res);
})

可以看到,比起.then的链式调用,async/await是不是更加简洁明了呢?

捕获错误

Promise.catch()

async.await中的try/catch