Promise和async/await的关系

96 阅读3分钟

Promise

关于Promise这里就不进行介绍,关于它的介绍可以看一下笔者之前发的这篇文章:传送门

Promise的实现可以查看这篇文章:传送门

async做了什么?

async function async1() {
    console.log('async1 start');
   return '我是async函数,来看看我返回了什么吧!'
}
console.log('start');
let async_1 = async1();
console.log(async_1);

image.png

从上面例子中我们可以很清晰的看到async做了什么:

async意为“异步”,作为一个关键字放在函数之前,表明此函数是一个异步函数,但是总体上代码任然是同步执行的;

async函数返回的是Promise对象,如果在async函数中使用了return关键字返回了值,这个值就会被Promise.resolve()包装成Promise对象(如果没有return,则会返回undefined),保证异步函数返回的始终是Promise对象;

await做了什么?

同样我们来通过一个例子来看一下await又做了什么

console.log('start');
function fn1() {
    console.log('fn1 start');
    return '我是fn1';
}
async function async1() {
    console.log('async1 start');
    let fn_1 = await fn1();
    console.log(fn_1);
    console.log('async1 end');
}
let async_1 = async1();
console.log('end');

image.png

之前我们说async函数总体上是同步执行的,但这个例子它却不是按序执行的,这是因为这里有await关键字,那await关键字做了什么,让代码没有按序执行呢?

await意为‘等待’,一般都认为await用于等待一个异步方法执行完成,但在语法上,await等待的是一个表达式,这个表达式的结果可以是Promise对象或其它值,所以,await后面可以接普通函数调用、直接量或者Promise对象,await只能在异步函数 async function中使用,否则会报错,把await放在async函数内部,await只在内部发生阻塞。

那await表达式的运算结果是怎么样的呢?

  • 如果它等到的不是一个 Promise 对象(如我们上面的例子),那 await 表达式的运算结果就是它等到的内容,

  • 如果他等到的是一个Promise对象,它会阻塞后面代码的执行,等着Promise对象resloved得到reslove的值,作为await表达式的运算结果

async/await和Promise比有什么优势呢?

同样的来个例子直观感受一下async/await相对于Promise的部分优势吧!

//这里使用setTimeout 来模拟我们再开发中遇到的异步任务
function adge(num) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(num + 500)
        }, 500)
    })
}

//多个业务之间值存在依赖
//async/await 版本
async function business() {
    let num = 0;
    num = await adge(num);
    num = await adge(num);
    num = await adge(num);
    num = await adge(num);
    num = await adge(num);
    console.log('我是async/await 版本的business',num);
}
//多个业务之间值存在依赖
//Promise.then 版本
function business1() {
    let num = 0;
    new Promise((resolve, reject) => {
        resolve(num);
    }).then(data => {
        num = adge(data);
        return num;
    }).then(data => {
        num = adge(data);
        return num;
    }).then(data => {
        num = adge(data);
        return num;
    }).then(data => {
        num = adge(data);
        return num;
    }).then(data => {
        num = adge(data);
        return num;
    }).then(data => {
        console.log('我是Promise 版本的business',data);
    })
}

通过这个例子我们可以显而易见的看到async/await简洁这一优势,但它还有其他优势:

  1. 简洁:用async/await就可以像写同步代码一样,节约了不少代码,不需要多层then方法,不需要写匿名函数处理Promise的resolve值,也不需要定义多余的data变量
  2. 错误处理:async/await让try/catch可以同时处理同步和异步错误。但在promise中,try/catch不能处理JSON.parse的错误,try/catche会被吞掉,我们需要使用.catch,这样错误处理代码非常冗余。
  3. 中间值:Promise传递中间值很麻烦,⽽async/await⼏乎是同步的写法,⾮常优雅
  4. 错误栈:Promise链中返回的错误栈没有给出错误发生位置的线索,而async/await中的错误栈会指向错误所在的函数
  5. 调试:Promise再调试时不能在返回表达式的箭头函数中设置断点,如果在.then代码块中设置断点,使用Step Over快捷键,调试器不会跳到下一个.then,因为它会跳过异步代码,调试器只能跟踪同步代码。