20170702-异步编程之 async await

async await

  • async await是异步编程的另外一种解决方案es6

  • async函数是对Generator函数的改进编程

async的基本用法

async函数

async函数返回一个 Promise 实例,能够使用then方法(为返回的Promise实例)添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操做完成,再接着执行函数体内后面的语句。服务器

  • 例 1:异步

clipboard.png

  • 上面代码是一个获取股票报价的函数,函数前面的async关键字,代表该函数内部有异步操做。调用该函数时,会当即返回一个Promise实例。async

  • async函数内部return语句返回的值,会成为then方法回调函数的参数。异步编程

Promise对象的状态变化

async函数返回的 Promise对象,必须等到内部全部await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操做执行完,才会执行then方法指定的回调函数。函数

await命令的基本用法

正常状况下,await命令后面是一个Promise实例,若是不是,会被转成一个当即resolvePromise实例。spa

async function f() {
  return await 123;
}

f().then(v => console.log(v))

等价于code

async function f() {
    return await new Promise(function(resolve){
        resolve(123)
    })
}
f().then(v => console.log(v))

等价于对象

async function f() {
    return await Promise.resolve('123')
}
f().then(v => console.log(v))
  • await语句的返回值是await命令后面Promise实例的结果(异步处理的结果)

function getResult() {
  return new Promise((resolve) => {
    resolve('result: 1000')  // resolve()方法的参数就是异步处理的结果
  });
}

async function asyncPrint() {
  const result = await getResult()  // 将异步处理的结果赋值给result
  return result
}

asyncPrint().then( (result) => { console.log(result) } ) //'result: 1000'

异常处理

若是await后面的异步操做出错,那么等同于async函数返回的 Promise 对象被reject

async function f() {
  await new Promise(function (resolve, reject) {
    throw new Error('出错了');
  });
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出错了

防止出错的方法,也是将其放在try...catch代码块之中。

async function f() {
  try {
    await new Promise(function (resolve, reject) {
      throw new Error('出错了');
    });
  } catch(e) {
  }
  return await('hello world');
}

使用注意

  • 若是await后面的异步操做出错,那么等同于async函数返回的 Promise 对象被reject,因此最好把await命令放在try...catch代码块中。

async function myFunction() {
  try {
    await somethingThatReturnsAPromise();
  } catch (err) {
    console.log(err);
  }
}

// 另外一种写法

async function myFunction() {
  await somethingThatReturnsAPromise()
  .catch(function (err) {
    console.log(err);
  });
}
  • 多个await命令后面的异步操做,若是不存在继发关系,最好让它们同时触发。

let foo = await getFoo();
let bar = await getBar();

上面代码中,getFoogetBar是两个独立的异步操做(即互不依赖),被写成继发关系(只有执行完getFoo操做,才能去执行getBar操做)。这样比较耗时,由于只有getFoo完成之后,才会执行getBar,彻底能够让它们同时触发。

解释:这里的getFoogetBar方法会返回两个Promise实例(假设是发起Ajax请求,请求foo和bar的内容),只有执行了方法,对应的操做才会执行,若是写成上面的形式,就会致使执行完getFoo的操做后(等待收到服务器的响应后),才能执行getBar的操做,这样就成了同步,比较耗时,所以能够将上面的写法修改,使得在等待getFoo执行完的时间内(在等待服务器响应的期间)去执行执行getBar

记住:当函数执行的时候,一旦遇到await就会先返回,等到异步操做完成,再接着执行函数体内后面的语句。

// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

上面两种写法,getFoogetBar都是同时触发,这样就会缩短程序的执行时间。

参考资料

ECMAScript 6 入门

相关文章
相关标签/搜索