async 与 await 可以使异步代码写法更加简洁,是在es2017引入的新特性,在最新版的nodejs及Chrome中都已经支持。
async 函数
const fetch = require('node-fetch');
// function getZhihuColumn(id) {
// const url = `https://zhuanlan.zhihu.com/api/columns/${id}`;
// fetch(url)
// .then(response => response.json())
// .then(column => {
// console.log(`NAME: ${column.title}`);
// console.log(`INTRO: ${column.intro}`);
// });
// }
使用async改写,使函数更加简洁
async function getZhihuColumn(id) {
const url = `https://zhuanlan.zhihu.com/api/columns/${id}`;
const response = await fetch(url);
const column = await response.json();
console.log(`NAME: ${column.title}`);
console.log(`INTRO: ${column.intro}`);
}
getZhihuColumn('feweekly')
将async函数用在promisechain中
// async function getZhihuColumn(id) {
// const url = `https://zhuanlan.zhihu.com/api/columns/${id}`;
// const response = await fetch(url);
// const column = await response.json();
// console.log(`NAME: ${column.title}`);
// console.log(`INTRO: ${column.intro}`);
// }
// function getZhihuColumn(id: any): Promise<any>
async function getZhihuColumn(id) {
const url = `https://zhuanlan.zhihu.com/api/columns/${id}`;
const response = await fetch(url);
return await response.json();
}
// function getZhihuColumn(id: any): Promise<any>
getZhihuColumn('feweekly')
.then(column => {
console.log(`NAME: ${column.title}`);
console.log(`INTRO: ${column.intro}`);
})
把任意类型的函数转换为async 函数
async 用在箭头函数
// async function getZhihuColumn(id) {
// const url = `https://zhuanlan.zhihu.com/api/columns/${id}`;
// const response = await fetch(url);
// return await response.json();
// }
// 箭头函数
const getZhihuColumn = async (id) => {
const url = `https://zhuanlan.zhihu.com/api/columns/${id}`;
const response = await fetch(url);
return await response.json();
}
// getZhihuColumn('feweekly')
// .then(column => {
// console.log(`NAME: ${column.title}`);
// console.log(`INTRO: ${column.intro}`);
//})
在全局作用域下使用async关键字是非法的 需要声明一个匿名的函数表达式
(async () => {
const columns = await getZhihuColumn('feweekly');
console.log(`NAME: ${column.title}`);
console.log(`INTRO: ${column.intro}`);
})()
// 另一种用法,在类的函数中使用async
class APIClient {
async getColumn(id) {
const url = `https://zhuanlan.zhihu.com/api/columns/${id}`;
const response = await fetch(url);
return await response.json();
}
}
(async () => {
const client = new APIClient();
const column = await client.getColumn('feweekly');
console.log(`NAME: ${column.title}`);
console.log(`INTRO: ${column.intro}`);
})()
处理async函数中的错误 的几种方式
async function getZhihuColumn(id) {
const url = `https://zhuanlan.zhihu.com/api/columns/${id}`;
const response = await fetch(url);
if (response.status !== 200) {
console.log(response.status.text)
throw new Error(response.status.text); // 1
}
return await response.json();
}
const showColumnInfo = async (id) => {
try { //2
const column = await getZhihuColumn(id);
console.log(`NAME: ${column.title}`);
console.log(`INTRO: ${column.intro}`);
} catch (error) {
console.log("test error")
console.log(error);
}
}
// showColumnInfo('feweekly2');
getZhihuColumn('feweekly1')
.then(column => {
console.log(`NAME: ${column.title}`);
console.log(`INTRO: ${column.intro}`);
}).catch(err=> { // 3
console.log("err2:" + err);
});
正确处理多个await操作的并行串行
添加await 的语句相当于处于一个线程中几个await串行执行,没有标记await的 并行执行。
const showColumnInfo = async () => {
try {
console.time('showColumnInfo');
// const column = await getZhihuColumn('feweekly');
// const toolingtips = await getZhihuColumn('toolingtips');
// 串行操作改为并行
const column2 = getZhihuColumn('feweekly');
const toolingtips2 = getZhihuColumn('toolingtips');
const column = await column2;
const toolingtips = await toolingtips2;
console.log(`NAME: ${column.title}`);
console.log(`INTRO: ${column.intro}`);
console.log(`NAME: ${toolingtips.title}`);
console.log(`INTRO: ${toolingtips.intro}`);
console.timeEnd('showColumnInfo');
} catch (error) {
console.log("test error")
console.log(error);
}
}
showColumnInfo();
使用Promise.all()让多个await操作并行
const showColumnInfo = async () => {
try {
console.time('showColumnInfo');
const [column, toolingtips] = await Promise.all([
getZhihuColumn('feweekly'),
getZhihuColumn('toolingtips')
])
console.log(`NAME: ${column.title}`);
console.log(`INTRO: ${column.intro}`);
console.log(`NAME: ${toolingtips.title}`);
console.log(`INTRO: ${toolingtips.intro}`);
console.timeEnd('showColumnInfo');
} catch (error) {
console.log("test error")
console.log(error);
}
}
showColumnInfo();
结合await和任意兼容then的代码
const bluebird = require('bluebird');
async function main() {
// await 有个隐式的调用 Promise.resolve()
// const number = await 8088
// // const number = await Promise.resolve(8088)
// console.log(number);
// await 可以和任何兼容promise的函数接口或者说带有then接口结合在一起使用
console.log('waiting...');
await bluebird.delay(2000);// 延时
console.log('done!');
}
main();
在for循环中使用await
const showColumnInfo2 = async () => {
try {
console.time('showColumnInfo');
// const names = ['feweekly', 'toolingtips']
// // 属于循环中的串行
// for (const name of names) {
// const column = await getZhihuColumn(name)
// console.log(`Name: ${name}`);
// }
const names = ['feweekly', 'toolingtips']
// 这里已经将函数调用执行,直接返回结果
const promises = names.map(name => getZhihuColumn(name))
// 属于循环中的并行,将函数结果做同步,函数调用过程做异步
for (const promise of promises) {
const column = await promise
console.log(`Name: ${column.title}`);
}
console.timeEnd('showColumnInfo');
} catch (error) {
console.log("test error")
console.log(error);
}
}
showColumnInfo2();