js异步之async/await

Posted tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js异步之async/await相关的知识,希望对你有一定的参考价值。

参考博客:

https://segmentfault.com/a/1190000007535316

https://www.runoob.com/w3cnote/es6-async.html

 

一、async

带async关键字的函数,是声明异步函数,返回值是promise对象,如果async关键字函数返回的不是promise,会自动用Promise.resolve()包装。

因此 async 函数总会返回一个 Promise 对象,可以使用 then 方法添加回调函数。

async function hello() {
    return \'hello\'
}

var res = hello();

console.log(res);  // Promise {<fulfilled>: "hello"}

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

所以,async 函数返回的是一个 Promise 对象,如果在函数中直接 return 一个值,async 会把这个值通过 Promise.resolve() 封装成 Promise 对象。
如果 async 函数没有返回值,它会返回 Promise.resolve(undefined)。

 

async 函数中可能会有 await 表达式,async 函数执行时,如果遇到 await 就会先暂停执行 ,等到触发的异步操作完成后,恢复 async 函数的执行并返回解析值。

await 关键字仅在 async function 中有效。如果在 async function 函数体外使用 await ,你只会得到一个语法错误。

 

二、await

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

await等待右侧表达式的结果,这个结果是promise对象或者其他值。

await针对所跟不同表达式的处理方式:

  • Promise 对象:await 会暂停执行,等待 Promise 对象 resolve,然后恢复 async 函数的执行并返回解析值。
  • 非 Promise 对象:直接返回对应的值。
// 返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。
// 如果一个 Promise 被传递给一个 await 操作符,await 将等待 Promise 正常处理完成并返回其处理结果。
function testAwait (x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}
 
async function helloAsync() {
  var x = await testAwait ("hello world");
  console.log(x); 
}
helloAsync();  // hello world

 

正常情况下,await 命令后面是一个 Promise 对象,它也可以跟其他值,如字符串,布尔值,数值以及普通函数。

function testAwait(){
   console.log("testAwait");
}
async function helloAsync(){
   await testAwait();
   console.log("helloAsync");
}
helloAsync();
// testAwait
// helloAsync

 

三、async/await的优势

async/await 的优势在于处理 then 链。
如果一个功能需要多个步骤(函数)协同工作,这时async/await 的优势就出来了。
单一的 Promise 链并不能发现 async/await 的优势,但是,如果需要处理由多个 Promise 组成的 then 链的时候,优势就能体现出来了。

// 我需要从taskInfo中一步一步的拿到username的值,那么函数如下

function taskInfo() {
    return new Promise(resolve => {
        var person = {
            "result": {
                "data": {"username": "zzz"}
            }
        }
        resolve(person);
    });
}

function step1() {
    var data = taskInfo();
    return data;
}

function step2(data) {
    return data.result;
}

function step3(data) {
    return data.data;
}

function step4(data) {
    return data.username;
}


// 用 Promise 的链式方式来实现

function main() {
    step1()
        .then(res1 => step2(res1))
        .then(res2 => step3(res2))
        .then(res3 => step4(res3))
        .then(response => {
            console.log(response);
        });
}

main();  // zzz


// 用 async/await 来实现
async function main() {
    var res1 = await step1();
    var res2 = await step2(res1);
    var res3 = await step3(res2);
    var response = await step4(res3);
    console.log(response);
}

main();  // zzz

结果和之前的 Promise 实现是一样的,但是这个代码清晰得多,几乎跟同步代码一样。

 

// 业务修改一下
function step1(n) {
    console.log(`step1 with ${n}`);
    return takeLongTime(n);
}

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

function step3(k, m, n) {
    console.log(`step3 with ${k}, ${m} and ${n}`);
    return takeLongTime(k + m + n);
}


// 先用 async/await 来写
async function doIt() {
    console.time("doIt");
    const time1 = 300;
    const time2 = await step1(time1);
    const time3 = await step2(time1, time2);
    const result = await step3(time1, time2, time3);
    console.log(`result is ${result}`);
    console.timeEnd("doIt");
}

doIt();


// 似乎和之前的示例没啥区别
// 那么写成 Promise 方式对比
function doIt() {
    console.time("doIt");
    const time1 = 300;
    step1(time1)
        .then(time2 => {
            return step2(time1, time2)
                .then(time3 => [time1, time2, time3]);
        })
        .then(times => {
            const [time1, time2, time3] = times;
            return step3(time1, time2, time3);
        })
        .then(result => {
            console.log(`result is ${result}`);
            console.timeEnd("doIt");
        });
}

doIt();

// 一堆参数处理,就是 Promise 方案的死穴—— 参数传递太麻烦了

 

以上是关于js异步之async/await的主要内容,如果未能解决你的问题,请参考以下文章

js异步回调Async/Await与Promise区别

Swift之深入解析异步函数async/await的使用与运行机制

JS/TS 中使用 async/await 的异步有界队列

JS不使用async/await解决数据异步/同步问题

JS不使用async/await解决数据异步/同步问题

第126篇: 异步函数(async和await)