异步回调Async Await与Promise区别

async await 它是基于promise的,为什么es6新增了这个?为了解决大量复杂不易读的Promise异步的问题才出现的,首先async await是有密切联系的!下面分别来介绍下它们的之前的关系!

1、async

async必须声明的是一个function!

async test= function () {
     return "我是个promise返回值" 
};
//语法错误  async必须声明的是一个function

async 是“异步”的意思,所以应该很好理解 async 用于申明一个 异步的function,返回的是一个Promise对象!

async function test() {
          return "我是个promise返回值"   // return Promise.resolve("我是个promise返回值")
      }
test();
// Promise {<fulfilled>: "我是个promise返回值"}

返回的是一个promise,不过可以理解为一个状态为fulfilled并且已经拿到了返回值为"我是个promise返回值"的promise 或者可以理解为return Promise.resolve(“我是个promise返回值”),同理如果没有返回值也是Promise.resolve(underfind),下面我们来验证下,后面接个回调函数!

async function test() {
    return "我是个promise返回值"
}
test().then((response) => {
    console.log(response); //我是个promise返回值
})

是这样的!那么对待async要像对待Promise一样去对待async的返回值!(有点绕口,知道这个意思就可以!)下面我们来看下 await

2、await

await必须是在这个async声明的函数内部使用,必须是直系,否则报错!

async function test() {
    function test1() {
        await 111;
    };
};
//Uncaught SyntaxError: await is only valid in async function

阮一峰老师说:async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。是这样吗?我们来测试下!

async function test() {
    await setTimeout(() => {
        console.log("我是不是最开始执行")
    }, 1000);
    console.log('我什么时候执行');
}
test();
//我什么时候执行
// 1s之后 我是不是最开始执行

我擦?不对啊! 怎么下面先开始执行了? 这里是有条件的,如果await后面是 promise对象,会将promise异步操作转为同步,等待 promise的resolve/reject 返回结果.,再接着执行函数体内后面的语句!继续测试下!

async function test() {
    await new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log("我是不是最开始执行")
        }, 1000);
    });
    console.log('我什么时候执行');
}
test();//我是不是最开始执行

怎么又不对?为什么下面 console.log(‘我什么时候执行’)没执行,是不是哪里写错了?原来是如果await的是一个promise对象,那么要等待这个对象解析完成,如果没有resolve或者reject那么后面的内容就不会执行!再改下!

async function test() {
    await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve();
            console.log("我是不是最开始执行")
        }, 1000);
    });
    console.log('我什么时候执行');
}
test(); // 1s之后 我是不是最开始执行    我什么时候执行

和阮老师说的貌似一致了!那么得出一个结论!如果await后面如果不是一个promise对象那么它就按正常的js顺序执行,先执行同步代码,当主线程空闲了,再去执行异步队列的任务!既然说到了这里,那么再讲深入一点点!js的执行机制大家应该知道!宏任务和微任务等(不懂的可以点击这里),看下面的一道面试题!

async function test() {
    console.log("async1");
    await new Promise((resolve, reject) => {
        resolve(1)
    });
    console.log('async2');
};
setTimeout(function () {
    console.log("setTimeout");
}, 0);
test();
new Promise(function (resolve) {
    console.log("promise1");
    resolve();
}).then(function () {
    console.log("promise2");
});
console.log('end');

相信很多人都会做错,那么我们来分析下!

  1. 执行第一轮宏任务,发现setTimeout是个宏任务,0秒后直接扔到宏任务异步队列!
  2. 执行test(),先输出"async1",直接执行await,因为后面是个promise对象,所以会"阻塞"后面的任务,直到拿到1这个结果,这里是重点发现console.log('async2')是个微任务,扔进微任务异步队列,执行完await后面的promise,那么后面的代码都是在promise.then()里面执行,所以console.log('async2')是个微任务!
  3. 执行new Promise,执行同步代码输出"promise1", then后面又是个微任务,扔进任务异步队列!
  4. 执行同步代码输出’end’!
  5. 一轮宏任务执行完毕,看下有没有微任务,执行第一个微任务输出’async2’,再执行第二个微任务"promise2",微任务执行结束,再执行第二轮宏任务!
  6. 最后执行宏任务输出"setTimeout"
  7. 所以执行结果是"async1",“promise1”,‘end’,‘async2’,“promise2”,“setTimeout”

上面说的偏题了,主要想说的是await后面如果不是一个promise对象那么它就是按正常js执行顺序(先同步后异步),是promise对象那么await后面的内容还是相当于在then执行,跟promise的区别在于如果等待的是一个promise对象,那么要等待这个对象解析完成,如果没有resolve或者reject那么后面的内容就不会执行

async function test() {
     console.log("async1");
     await new Promise((resolve, reject) => {
         resolve()
     });
     console.log('async2');
 };
 //等价于
 async function test() {
     console.log("async1");
     await new Promise((resolve, reject) => {
         resolve()
     }).then(() => console.log('async2'));
 };

async function fn2() {
    await 2
    console.log(2)
}
//等价于
async function fn2() {
    Promise.resolve(2).then(() => console.log(2))
}

接着正题说,那么await有返回值吗?返回值是什么?

async function test() {
    let result = await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('返回的值');
        }, 1000);
    });
   console.log(result) //返回的值
   // 等价于Promise.resolve(result).then(() => console.log(result));
   return result;
};
test().then((data) =>
    console.log(data)//返回的值
)

看上面的例子可以发现await 的返回值就是promise的resolve/reject 返回结果,然后通过执行async函数 retrun出来,相当于 Promise.resolve("返回结果")!

当async函数抛出异常时或者await 的返回值reject状态 ,Promise 的 reject 方法也会传递这个异常值!

async function test() {
    throw Error("获取错误")
};
test().catch((error) =>
    console.log(error)
);
//Error: 获取错误

async function test() {
    let result = await new Promise((resolve, reject) => {
        setTimeout(() => {
            reject("获取返回值失败");
        }, 1000);
    });
    console.log(result) //失败后后面代码不执行了
    return result;
};
test().catch((error) =>
    console.log(error)//获取返回值失败
);

3、async await 和promise相比的优势

async await是promise的进化版,async await 相比原来的Promise的优势在于处理 then链,不必把回调嵌套在then中,只要await 即可 我们来模拟下一个场景,有3个请求,但是有顺序的,必须要先执行第一个,再执行第二个,最后执行第三个,并且1秒后执行第一个请求,执行完第一个请求后,3秒后执行第二个请求,执行完第二个请求后,5秒后执行第三个请求!平时工作中应该很多这种需求!

promise会这样写

let request1 = (time) => {
     return new Promise((resolve, reject) => {
         setTimeout(() => {
             resolve('request1返回的值');
         }, time * 1000);
     });
 };

 let request2 = (time) => {
     return new Promise((resolve, reject) => {
         setTimeout(() => {
             resolve('request2返回的值');
         }, time * 1000);
     });
 };

 let request3 = (time) => {
     return new Promise((resolve, reject) => {
         setTimeout(() => {
             resolve('request3返回的值');
         }, time * 1000);
     });
 };

 request1(1).then((data) => {
     console.log(data);//request1返回的值
     return request2(3)
 }).then((data) => {
     console.log(data);//request3返回的值
     return request3(5)
 }).then((data) => {
     console.log(data)//request3返回的值
 })

async await 会这样写

async function request() {
    let resolve1 = await request1(1);
    console.log(resolve1);
    resolve2 = await request2(3);
    console.log(resolve2);
    resolve3 = await request3(5);
    console.log(resolve3);
}
request();

是不是没有冗余的长长的链式代码,语义化也非常清楚,看起来很舒服!,本来想把async await 如何捕获异常也写了,想不想还是下篇再补完吧!

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值