1 为什么要引入async function?
详情可以参考: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)
执行结果如下:
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的结果却是这样!
显然,这种写法也有问题:
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数组变成了字串数组了
再看下代码,会发现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