async和await

由一道面试题引发的思考……

这本来是个事件循环的题,然后我啪就准备开始写,看完之后,一切答案了然于心,一运行又啪一下啊,答案不一样,是完全不一样,所以我就开始想为什么。最终还是因为我没能真正的掌握async和await这个东西。。。

async和await

事件循环经典题镇楼

经典例题1

这道题是相对来说比较简单的,只是用到了最基本的一些setTimeout、promise以及打印事件。

做这类型的题目前,我们只要时刻记着,JS是单线程,执行的时候是按照同步代码执行=>微任务=>宏任务来执行的,即可很简单的做出这样的题目。

console.log('start')

setTimeout(function() {
  console.log('setTimeout')
}, 0)

Promise.resolve().then(function() {
  console.log('promise1')
}).then(function() {
  console.log('promise2')
})

console.log('end')
//答案是:
start
end
promise1
promise2
setTimeout

经典例题2

这道题也是相当经典的一道题,那位博主说是头条的题目。(PS:看看题目你们就应该能懂我未申报么要写这一篇博客了把,呜呜呜~

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
async function async2() {
    console.log('async2');
}
console.log('script start');
setTimeout(function() {
    console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
});
console.log('script end');

我们脑子想的答案是async是微任务,肯定是在后面执行的,所以答案很简单嘛。就按照上面的来,结果一打印,啪一看,答案错了。😂

我们现在就来聊一聊async和await这两个东西吧。在英语词典中,sync是同步的意思,那async就是异步的简写,那么await就是async wait的简写

asyncawait

async

async是用于声明一个function是异步的,而await用于等待一个异步方法执行完成。

那么,该怎么使用它们呢?

首先我们要知道一个点:await只能出现在async函数中。

我们来看看async的返回值先:

async function testAsync(){
    return 'hello';
}
var res=testAsync();
console.log(res);   //Promise {‘hello’}

async函数返回的值是一个Promise对象,我们可以直接看到这个信息。

所以我们能很快的得出,async函数(函数表达式、函数语句)会返回Promise对象,,如果在函数中return一个直接量,async函数会直接通过Promise.resolve()将其封装为Promise对象。

Promise.resolve(x)可以看作是new Promise(resolve=>{resolve(x)})的简写,用于快速封装字面量对象或者是其他对象,将其封装为Porsmie的实例。

async返回的值是一个promise对象,所以我们应该使用.then方法来接收返回值。除此之外,我们还可以使用await方法来获取返回值。

肯定就会有人问了,那没有返回值该怎么办呢?

照葫芦画瓢呗,有返回值就返回你想返回的值,没有的话就是undefined呗,返回值为Promise.resolve(undefined)

await

wait字面意思就是等待的意思,那么他等待的是什么呢?

按照官方语法说明,await等待的是一个表达式,这个表达式计算结果是Promise对象或者是其他值。

async返回的是一个Promise对象,那就可以说是await在等待async函数的返回值。await后面不仅仅可以接Promise对象还可以等任意表达式的结果。

  • 如果返回值是一个Promise对象,那么await就要开始忙碌了,这个await会阻塞后面的代码,等着Promise对象resolve,然后得到resolve的值,作为await表达式的运算结果
  • 如果返回值不是一个Pormise对象,那么await表达式的运算结果就是它等到的结果。

在我看来,await的存在就是为了配合async的,因为async相当于是定义了新的promise定义方法,但是如果直接使用.then,代码维护起来不太方便,而且不太美观,就定义一个新的方法await来处理异步操作返回的值。

async/await的用处

我们学习一个东西,肯定要知其所以然,更要懂得它是怎么使用的。

替换链式调用

Promise的链式调用是Promise的用法之一。Promise.then链来解决多层回调的问题,现在我们又要用async/await来进一步优化它。

function takeLongTime(n) {
    return new Promise(resolve => {
        setTimeout(() => resolve(n + 200), n);
    });
}

function step1(n) {
    console.log(`step1 with ${n}`);
    return takeLongTime(n);
}

function step2(n) {
    console.log(`step2 with ${n}`);
    return takeLongTime(n);
}

function step3(n) {
    console.log(`step3 with ${n}`);
    return takeLongTime(n);
}

我们需要链式调用的话肯定就需要花费很大的功夫了,这个时候,我们就可以使用async和await来实现。

async function doIt(){
    console.time("doit");
    const time1=300;
    const time2=await step1(time1);
    const time2=await stpe2(time2);
    const time3=await step3(time3);
    console.log(`result is ${result}`);
    console.timeEnd('doIt');
}
doIt();

这种写法是不是比promise.then()清晰多了。

缺点

再好的方法也有缺点,async方法不可能没有缺点。

async/await会使得自己的代码被阻塞,导致之后的代码,会受到大量的await的影响而相继变慢。