Async functions in ES8

1 为什么要引入async function?

092951_LXOx_2510955.png

详情可以参考:https://derickbailey.com/2017/04/18/you-need-es7s-async-functions-heres-why/?utm_source=javascriptweekly&utm_medium=email

 

2 定义

  • 声明:
async function foo () {}
  • 表达式
const foo = async function () {}
  • 方法定义
let obj = {async foo () {}}
  • 箭头函数(类似表达式)
const foo = async () => {}

 

3 返回值,总是Promises

// fullfill promise
async function asyncFunc() {
    return 123;
}

// 调用
asyncFunc()
.then(x => console.log(x));


// rejecting promise
async function asyncFunc() {
    throw new Error('Problem!');
}

// 调用
asyncFunc()
.catch(err => console.log(err));
    // Error: Problem!

 

4 如何处理async function的 返回值 --- await !

注意: await关键字只能在async function 里面使用

async function asyncFunc() {
    const result = await otherAsyncFunc();
    console.log(result);
}

// Equivalent to:
function asyncFunc() {
    return otherAsyncFunc()
    .then(result => {
        console.log(result);
    });
}

 

下面这个是自己写的例子

async function foo () {
 return 'foo'
}

async function boo () {
  let result = await foo()
  console.log(result)
  return result + 'boo'
}

boo().then((re) => {
  console.log(re);
})

 

  • 顺序处理多个 async function 返回值
async function asyncFunc() {
    const result1 = await otherAsyncFunc1();
    console.log(result1);
    const result2 = await otherAsyncFunc2();
    console.log(result2);
}

// Equivalent to:
function asyncFunc() {
    return otherAsyncFunc1()
    .then(result1 => {
        console.log(result1);
        return otherAsyncFunc2();
    })
    .then(result2 => {
        console.log(result2);
    });
}

 

  • 并列处理多个 async function 返回值---使用Promise.all
async function asyncFunc() {
    const [result1, result2] = await Promise.all([
        otherAsyncFunc1(),
        otherAsyncFunc2(),
    ]);
    console.log(result1, result2);
}

// Equivalent to:
function asyncFunc() {
    return Promise.all([
        otherAsyncFunc1(),
        otherAsyncFunc2(),
    ])
    .then([result1, result2] => {
        console.log(result1, result2);
    });
}

 

自己写的例子:

async function sayHi() {
  return 'Hi'
}

async function sayBye() {
  return 'Bye'
}

async function asyncFunc() {
  const [result1, result2] = await Promise.all([
    sayHi(),
    sayBye()
  ])
  console.log(result1, result2)
}

asyncFunc()

 

 

5 进一步理解async function

  • 在ES6中,引入了Promise 处理异步函数的结果

function fetchJson(url) {
    return fetch(url)
    .then(request => request.text())
    .then(text => {
        return JSON.parse(text);
    })
    .catch(error => {
        console.log(`ERROR: ${error.stack}`);
    });
}

// 调用
fetchJson('http://example.com/some_file.json')
.then(obj => console.log(obj));

 

  • 同样,也可以使用使用generator处理异步函数的结果,最常用的比如co 这个js库

const fetchJson = co.wrap(function* (url) {
    try {
        let request = yield fetch(url);
        let text = yield request.text();
        return JSON.parse(text);
    }
    catch (error) {
        console.log(`ERROR: ${error.stack}`);
    }
});

 

  • 简单又好用的async function 上场了,你会发现,和co的语法很像,只是把 yield 换成了 await

async function fetchJson(url) {
    try {
        let request = await fetch(url);
        let text = await request.text();
        return JSON.parse(text);
    }
    catch (error) {
        console.log(`ERROR: ${error.stack}`);
    }
}

 

  • async function 的执行过程

开始调用是同步的,执行过程是异步的,返回结果当然也是异步的,下面看个例子

async function asyncFunc() {
  console.log('asyncFunc()'); // (A)
  return 'abc';
}
asyncFunc().
then(x => console.log(`Resolved: ${x}`)); // (B)
console.log('main'); // (C)

执行结果如下:

153707_HHCJ_2510955.png

line A:  异步函数开始执行,注意是同步的,执行结果返回Promise

line C: 函数执行继续

line B:  Promise的结果通知,异步执行

 

 

6 使用 await 时的要点

  • 不要忘记await
async function asyncFunc() {
    const value = otherAsyncFunc(); // missing `await`!
    ···
}

这样可能会导致value的结果不是你想要的

  • 当async function 没有返回值时,await 确保 后面的语句在该异步函数执行完后才执行
async function foo() {
    await step1(); // (A)
    ···
}

 

  • await 顺序执行,Promise.all() 并列执行
async function foo() {
    const result1 = await asyncFunc1();
    const result2 = await asyncFunc2();
}


使用Promise.all()加速执行,只需要等待一个Promise, 一个含所有2个元素的数组
async function foo() {
    const [result1, result2] = await Promise.all([
        asyncFunc1(),
        asyncFunc2()
    ]);
}

 

 

7 async function 和 callbacks

async function的 callback 中不能有 await,但是 callback 却可以是async function, 这样就可以使用await了

async function downloadContent(urls) {
    return urls.map(url => {
        // Wrong syntax!
        const content = await httpGet(url);
        return content;
    });
}

// await 出现在箭头函数中是不合法的

但下面这种写法确实合法的,给callback加上async关键字

​
async function downloadContent(urls) {
    return urls.map(async (url) => {
        const content = await httpGet(url);
        return content;
    });
}

 

给个例子

let colors = [
  'red', 'blue', 'green'
]

async function lightColor (color) {
  return 'light ' + color
}

async function asyncFunc() {
  return colors.map(async (color) => { // 加上async 关键字
    const content = await lightColor(color);
    return content
  })
}

asyncFunc().then((res) => {
  console.log(res)
})

 

但res的结果却是这样!

170521_B4iS_2510955.png

 

显然,这种写法也有问题:

1 返回的结果不是Array of string, 而是 Array of Promises

2 urls.map()循环都结束了,callback的异步函数还没有结束,因为await只能暂停它周围的代码,不能暂停downloadContent里面函数的执行

怎么解决呢?

通过Promise.all(), 它可以将Array of Promises 转化为一个Promise for an Array

let colors = [
  'red', 'blue', 'green'
]

async function lightColor (color) {
  return 'light ' + color
}

async function asyncFunc() {
  const promiseArray = colors.map(async (color) => {
    const content = await lightColor(color);
    return content
  })

  return await Promise.all(promiseArray) // 使用Promise.all()
}

asyncFunc().then((res) => {
  console.log(res)
})

 

结果就从Promise数组变成了字串数组了

171507_BvqM_2510955.png

 

再看下代码,会发现callback for map并没有对lightColor()的结果做很多处理,只是循环,所以,这里可以去掉callback中的async

async function asyncFunc() {
  const promiseArray = colors.map(color => lightColor(color)) // callback中去掉async
  return await Promise.all(promiseArray)
}

 

使用async function 效率并不高,因为await unwrap Promise.all()的结果, return 又会wrap 结果,但return  不会 wrap   Promises, 所以,我们可以直接返回Promise.all()的结果

async function asyncFunc() {
  const promiseArray = colors.map(color => lightColor(color))
  return Promise.all(promiseArray)  // 去掉await
}

 

参考资料:http://exploringjs.com/es2016-es2017/ch_async-functions.html#_handling-results-and-errors-of-asynchronous-computations-via-await

转载于:https://my.oschina.net/u/2510955/blog/893536

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值