Async Await使用场景

Posted 前端e站

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Async Await使用场景相关的知识,希望对你有一定的参考价值。

前言:一般我们都用await去等待一个async函数完成,不过按语法说明,await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值,所以,await后面实际可以接收普通函数调用或者直接量。

async 函数的实现

前面一篇文章详细介绍了Async函数,点击回顾上期内容:Javascript中的Async

// async 函数的实现,就是将 Generator 函数和自动执行器,包装在一个函数里。
async function fn(args)
  // ...

// 等同于
function fn(args) 
  return spawn(function*() 
    // ...
  ); 

async 函数的用法

同 Generator 函数一样,async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。


// 立即返回一个Promise对象
async function getStockPriceByName(name) 
  var symbol = await getStockSymbol(name);
  var stockPrice = await getStockPrice(symbol);
  return stockPrice;


getStockPriceByName('goog').then(function (result)
  console.log(result);
);
// 指定多少毫秒后输出一个值。
function timeout(ms) 
  return new Promise((resolve) => 
    setTimeout(resolve, ms);
  );


async function asyncPrint(value, ms) 
  await timeout(ms);
  console.log(value)


asyncPrint('hello world', 100);
// 100毫秒以后,输出"hello world"

Async Await使用场景

当需要用到promise链式调用的时候,就体现出Async Await的优势;

有这么一个业务需要分步完成,每个步骤都是异步的,而且依赖上一步的执行结果,甚至依赖之前每一步的结果,就可以使用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(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 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();

await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try...catch 代码块中,或者await后的Promise添加catch回调。

await read('1.txt','utf8').catch(function(err)
    console.log(err);
)

await 只能出现在 async 函数中,如果用在普通函数,就会报错。

async function dbFuc(db) 
  let docs = [, , ];
  // 报错
  docs.forEach(function (doc) 
    await db.post(doc);
  );

上面代码会报错,因为 await 用在普通函数之中了。但是,如果将 forEach 方法的参数改成 async 函数,也有问题。

async function dbFuc(db) 
  let docs = [, , ];
  // 可能得到错误结果
  docs.forEach(async function (doc) 
    await db.post(doc);
  );

上面代码可能不会正常工作,原因是这时三个 db.post 操作将是并发执行,也就是同时执行,而不是继发执行。正确的写法是采用 for 循环。

async function dbFuc(db) 
  let docs = [, , ];
  for (let doc of docs) 
    await db.post(doc);
  

如果确实希望多个请求并发执行,可以使用 Promise.all 方法。

async function dbFuc(db) 
  let docs = [, , ];
  let promises = docs.map((doc) => db.post(doc));

  let results = await Promise.all(promises);
  console.log(results);


// 或者使用下面的写法

async function dbFuc(db) 
  let docs = [, , ];
  let promises = docs.map((doc) => db.post(doc));

  let results = [];
  for (let promise of promises) 
    results.push(await promise);
  
  console.log(results);

总的来说,async函数有以下几点好处

  • 解决了回调地狱的问题

  • 支持并发执行

  • 可以添加返回值 return xxx

  • 可以在代码中添加try/catch捕获错误

以上是关于Async Await使用场景的主要内容,如果未能解决你的问题,请参考以下文章

Async Await使用场景

Async Await使用场景

async / await 的串行和并行

JavaScript之顶级await,不需要使用async声明即可使用awaitimport

JS async和await关键字

c# await 不能作用于 async上?