异步操作之async

上篇文章讲述了Promise,这次来看一下async。
async函数(包含函数语句、函数表达式、Lambda表达式)会返回一个Promise对象,如果在函数中return一个直接量,async会把这个直接量通过Promise.resolve()封装成Promise对象。由此可以知道,async之所以能够进行异步操作,其实还是Promise在起作用。

async function testAsync() {
    return 'hello async'
}
const result = testAsync();
console.log(result);
//Promise对象

async函数返回的是一个Promise对象,所以在最外层不能用await获取其返回值的情况下,我们应该用原来的方式:then()链来处理这个Promise对象

testAsync().then(v => {
    console.log(v);
})
//hello async

如果async函数没有返回值,它会返回Promise.resolve(undefined)
Promise的特点——无等待,所以在没有await的情况下执行async函数,它会立即执行,返回一个Promise对象,并且,绝不会阻塞后面的语句。这和普通返回Promise对象的函数并无二致。
一般来说,都认为await是在等待一个async函数完成。不过按语法说明,await等待的是一个表达式,这个表达式的计算结果是Promise对象或者其它值(没有特殊限定)。
因为async函数返回一个Promise对象,所以await可以用于等待一个async函数的返回值——这也可以说是await在等async函数,但要清楚,它等的实际是一个返回值。注意到await不仅仅用于等Promise对象,它可以等任意表达式的结果,所以,await后面实际是可以接普通函数调用或者直接量的。

function getSomething() {
    return 'something';
}
async function testAsync1() {
    return Promise.resolve('hello async');
}
async function test() {
    const v1 = await getSomething();
    const v2 = await testAsync1();
    console.log(v1, v2);
}
test();
//something 
//hello async

await是个运算符,用于组成表达式,await表达式的运算结果取决于它等的东西。
如果它等的不是一个Promise对象,那await表达式的运算结果就是它等到的东西。
如果它等到的是一个Promise对象,await就忙起来了,它会阻塞后面的代码,等着Promise对象resolve,然后得到resolve的值,作为await表达式的运算结果。
async函数调用不会造成阻塞,它内部所有的阻塞都被封装在一个Promise对象中异步执行。await用在async函数中,就是为了阻塞后面的代码,等待Promise对象执行resolve。
async会将其后的函数(函数表达式或Lambda)的返回值封装成一个Promise对象,而await会等待这个Promise完成,并将其resolve的结果返回出来。

function takeLongTime() {
    return new Promise(resolve => {
        setTimeout(() => resolve("long_time_value"), 1000);
    })
}
takeLongTime().then(v => {
    `这里写代码片`console.log('got', v);//
    1s后给出返回值got long_time_value
})

async function test1() {
    const v = await takeLongTime();
    console.log(v);
    //1s后给出返回值long_time_value
}
test1();

async/await的优势在于处理then链
单一的Promise链并不能发现async/await的优势,但是,如果需要处理由多个Promise组成的then链的时候,优势就能体现出来了(Promise通过then链来解决多层回调的问题,现在又用async/await来进一步优化它)。
例子一:
传入参数n,表示这个函数执行的时间(用于毫秒)
执行的结果是n + 200,这个值将用于下一步骤

function takeLongTime1(n) {
return new Promise(resolve => {
    setTimeout(() => resolve(n + 200), n);
})
}
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime1(n)
}
function step2(n) {
console.log(`step2 with ${n}`);
return takeLongTime1(n)
}
function step3(n) {
console.log(`step3 with ${n}`);
return takeLongTime1(n)
}

用Promise方式来实现这三个步骤的处理

function doIt() {
    console.time("doIt");
    const time1 = 300;
    step1(time1)
        .then(time2 => step2(time2))
        .then(time3 => step3(time3))
        .then(result => {
            console.log(`result is ${result}`);
            console.timeEnd("doIt");
        })
}
doIt();
// step1 with 300
// step2 with 500
// step3 with 700
// result is 900
// doIt: 1505.547119140625ms

用async/await来实现

async function doIt1() {
    console.time("doIt1");
    const time1 = 300;
    const time2 = await step1(time1);
    const time3 = await step2(time2);
    const result = await step3(time3);
    console.log(`result is ${result}`);
    console.timeEnd("doIt1")
}
doIt1();
// step1 with 300
// step2 with 500
// step3 with 700
// result is 900
// doIt: 1505.547119140625ms

两种方式的实现是一样的,但是使用async/await编写的代码看起来更加清晰,几乎和同步代码一样。
例子二:
把业务要求改一下,仍然是三个步骤,但每一个步骤都需要之前每个步骤的结果。

function step4(n) {
    console.log(`step4 with ${n}`);
    return takeLongTime1(n);
}
function step5(m, n) {
    console.log(`step5 with ${m} and ${n}`);
    return takeLongTime1(m + n);
}
function step6(k, m, n) {
    console.log(`step6 with ${k}, ${m} and ${n}`);
    return takeLongTime1(k + m + n);
}

Promise方式实现,传递参数太麻烦了

function doIt2() {
    console.time("doIt2");
    const time1 = 300;
    step4(time1)
        .then(time2 => {
            return step5(time1, time2)
                .then(time3 => [time1, time2, time3])
        })
        .then(times => {
            const [time1, time2, time3] = times;
            return step6(time1, time2, time3);
        })
        .then(result => {
            console.log(`result is ${result}`);
            console.timeEnd("doIt2");
        })
}
doIt2();
//step4 with 300
//step5 with 300 and 500 
//step6 with 300, 500 and 1000 
//result is 2000
//doIt2: 2906.326904296875ms

然而async/await还是一直的清晰明了

async function doIt3() {
    console.time("doIt3");
    const time1 = 300;
    const time2 = await step4(time1);
    const time3 = await step5(time1, time2);
    const result = await step6(time1, time2, time3);
    console.log(`result is ${result}`);
    console.timeEnd("doIt3");
}
doIt3();
//step4 with 300
//step5 with 300 and 500 
//step6 with 300, 500 and 1000 
//result is 2000
//doIt2: 2907.419189453125ms

这下你懂得async/await的优势了吧。

猜你喜欢

转载自blog.csdn.net/weixin_40970987/article/details/81982868