浅谈async/await

Posted coder-sherry

tags:

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

ES7的async/await语法在2016年就已经提出来了,惭愧的是我最近才接触使用,,下面来聊聊

解决了什么问题

在async/await之前,我们有三种方式写异步代码

  1. 嵌套回调

  2. 以Promise为主的链式回调

  3. 使用Generators

但是,这三种写起来都不够优雅,ES7做了优化改进,async/await应运而生,async/await相比较Promise 对象then 函数的嵌套,与 Generator 执行的繁琐(需要借助co才能自动执行,否则得手动调用next() ), Async/Await 可以让你轻松写出同步风格的代码同时又拥有异步机制,更加简洁,逻辑更加清晰。

async/await特点

  1. async/await更加语义化,async 是“异步”的简写,async function 用于申明一个 function 是异步的; await,可以认为是async wait的简写, 用于等待一个异步方法执行完成;

  2. async/await是一个用同步思维解决异步问题的方案(等结果出来之后,代码才会继续往下执行)

  3. 可以通过多层 async function 的同步写法代替传统的callback嵌套

async function语法

  • 自动将常规函数转换成Promise,返回值也是一个Promise对象

  • 只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数

  • 异步函数内部可以使用await

async function name([param[, param[, ... param]]]) { statements }
name: 函数名称。
param:  要传递给函数的参数的名称
statements: 函数体语句。
返回值: 返回的Promise对象会以async function的返回值进行解析,或者以该函数抛出的异常进行回绝。

技术分享图片

await语法

  • await 放置在Promise调用之前,await 强制后面点代码等待,直到Promise对象resolve,得到resolve的值作为await表达式的运算结果

  • await只能在async函数内部使用,用在普通函数里就会报错
[return_value] = await expression;

expression:  一个 Promise  对象或者任何要等待的值。

返回值:返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。

技术分享图片

错误处理

在async函数里,无论是Promise reject的数据还是逻辑报错,都会被默默吞掉,所以最好把await放入try{}catch{}中,catch能够捕捉到Promise对象rejected的数据或者抛出的异常

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {reject(‘error‘)}, ms);  //reject模拟出错,返回error

  });

}

async function asyncPrint(ms) {

  try {

     console.log(‘start‘);

     await timeout(ms);  //这里返回了错误

     console.log(‘end‘);  //所以这句代码不会被执行了

  } catch(err) {

     console.log(err); //这里捕捉到错误error

  }

}

asyncPrint(1000);

如果不用try/catch的话,也可以像下面这样处理错误(因为async函数执行后返回一个promise)

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {reject(‘error‘)}, ms);  //reject模拟出错,返回error

  });

}

async function asyncPrint(ms) {

  console.log(‘start‘);

  await timeout(ms)

  console.log(‘end‘);  //这句代码不会被执行了

}

asyncPrint(1000).catch(err => {

    console.log(err); // 从这里捕捉到错误

});

如果你不想让错误中断后面代码的执行,可以提前截留住错误,像下面

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {

        reject(‘error‘)

    }, ms);  //reject模拟出错,返回error

  });

}

async function asyncPrint(ms) {

  console.log(‘start‘);

  await timeout(ms).catch(err => {  // 注意要用catch

console.log(err) 

  })

  console.log(‘end‘);  //这句代码会被执行

}

asyncPrint(1000);

使用场景

多个await命令的异步操作,如果不存在依赖关系(后面的await不依赖前一个await返回的结果),用Promise.all()让它们同时触发

function test1 () {
    return new Promise((resolve, reject) => {

        setTimeout(() => {

            resolve(1)

        }, 1000)

    })

}

function test2 () {

    return new Promise((resolve, reject) => {

        setTimeout(() => {

            resolve(2)

        }, 2000)

    })

}

async function exc1 () {

    console.log(‘exc1 start:‘,Date.now())

    let res1 = await test1();

    let res2 = await test2(); // 不依赖 res1 的值

    console.log(‘exc1 end:‘, Date.now())

}

async function exc2 () {

    console.log(‘exc2 start:‘,Date.now())

    let [res1, res2] = await Promise.all([test1(), test2()])

    console.log(‘exc2 end:‘, Date.now())

}

exc1();

exc2();

exc1 的两个并列await的写法,比较耗时,只有test1执行完了才会执行test2

你可以在浏览器的Console里尝试一下,会发现exc2的用Promise.all执行更快一些

技术分享图片

兼容性

技术分享图片

在自己的项目中使用

通过 babel 来使用。

只需要设置 presets 为 stage-3 即可。

 安装依赖:

npm install babel-preset-es2015 babel-preset-stage-3 babel-runtime babel-plugin-transform-runtime

修改.babelrc:

 "presets": ["es2015", "stage-3"],

 "plugins": ["transform-runtime"]

    
这样就可以在项目中使用 async 函数了。

技术分享图片

---恢复内容结束---

ES7的async/await语法在2016年就已经提出来了,惭愧的是我最近才接触使用,,下面来聊聊

解决了什么问题

在async/await之前,我们有三种方式写异步代码

  1. 嵌套回调

  2. 以Promise为主的链式回调

  3. 使用Generators

但是,这三种写起来都不够优雅,ES7做了优化改进,async/await应运而生,async/await相比较Promise 对象then 函数的嵌套,与 Generator 执行的繁琐(需要借助co才能自动执行,否则得手动调用next() ), Async/Await 可以让你轻松写出同步风格的代码同时又拥有异步机制,更加简洁,逻辑更加清晰。

async/await特点

  1. async/await更加语义化,async 是“异步”的简写,async function 用于申明一个 function 是异步的; await,可以认为是async wait的简写, 用于等待一个异步方法执行完成;

  2. async/await是一个用同步思维解决异步问题的方案(等结果出来之后,代码才会继续往下执行)

  3. 可以通过多层 async function 的同步写法代替传统的callback嵌套

async function语法

  • 自动将常规函数转换成Promise,返回值也是一个Promise对象

  • 只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数

  • 异步函数内部可以使用await

async function name([param[, param[, ... param]]]) { statements }
name: 函数名称。
param:  要传递给函数的参数的名称
statements: 函数体语句。
返回值: 返回的Promise对象会以async function的返回值进行解析,或者以该函数抛出的异常进行回绝。

技术分享图片

await语法

  • await 放置在Promise调用之前,await 强制后面点代码等待,直到Promise对象resolve,得到resolve的值作为await表达式的运算结果

  • await只能在async函数内部使用,用在普通函数里就会报错
[return_value] = await expression;

expression:  一个 Promise  对象或者任何要等待的值。

返回值:返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。

技术分享图片

错误处理

在async函数里,无论是Promise reject的数据还是逻辑报错,都会被默默吞掉,所以最好把await放入try{}catch{}中,catch能够捕捉到Promise对象rejected的数据或者抛出的异常

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {reject(‘error‘)}, ms);  //reject模拟出错,返回error

  });

}

async function asyncPrint(ms) {

  try {

     console.log(‘start‘);

     await timeout(ms);  //这里返回了错误

     console.log(‘end‘);  //所以这句代码不会被执行了

  } catch(err) {

     console.log(err); //这里捕捉到错误error

  }

}

asyncPrint(1000);

如果不用try/catch的话,也可以像下面这样处理错误(因为async函数执行后返回一个promise)

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {reject(‘error‘)}, ms);  //reject模拟出错,返回error

  });

}

async function asyncPrint(ms) {

  console.log(‘start‘);

  await timeout(ms)

  console.log(‘end‘);  //这句代码不会被执行了

}

asyncPrint(1000).catch(err => {

    console.log(err); // 从这里捕捉到错误

});

如果你不想让错误中断后面代码的执行,可以提前截留住错误,像下面

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {

        reject(‘error‘)

    }, ms);  //reject模拟出错,返回error

  });

}

async function asyncPrint(ms) {

  console.log(‘start‘);

  await timeout(ms).catch(err => {  // 注意要用catch

console.log(err) 

  })

  console.log(‘end‘);  //这句代码会被执行

}

asyncPrint(1000);

使用场景

多个await命令的异步操作,如果不存在依赖关系(后面的await不依赖前一个await返回的结果),用Promise.all()让它们同时触发

function test1 () {
    return new Promise((resolve, reject) => {

        setTimeout(() => {

            resolve(1)

        }, 1000)

    })

}

function test2 () {

    return new Promise((resolve, reject) => {

        setTimeout(() => {

            resolve(2)

        }, 2000)

    })

}

async function exc1 () {

    console.log(‘exc1 start:‘,Date.now())

    let res1 = await test1();

    let res2 = await test2(); // 不依赖 res1 的值

    console.log(‘exc1 end:‘, Date.now())

}

async function exc2 () {

    console.log(‘exc2 start:‘,Date.now())

    let [res1, res2] = await Promise.all([test1(), test2()])

    console.log(‘exc2 end:‘, Date.now())

}

exc1();

exc2();

exc1 的两个并列await的写法,比较耗时,只有test1执行完了才会执行test2

你可以在浏览器的Console里尝试一下,会发现exc2的用Promise.all执行更快一些

技术分享图片

兼容性

技术分享图片

在自己的项目中使用

通过 babel 来使用。

只需要设置 presets 为 stage-3 即可。

 安装依赖:

npm install babel-preset-es2015 babel-preset-stage-3 babel-runtime babel-plugin-transform-runtime

修改.babelrc:

 "presets": ["es2015", "stage-3"],

 "plugins": ["transform-runtime"]

    
这样就可以在项目中使用 async 函数了。

技术分享图片



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

Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题

Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题

Async/Await替代Promise的理由

promise与async和await的区别

Async/Await是这样简化JavaScript代码的

使用 Async/Await 控制哪些代码停止