async函数的是什么?
一句话,async 函数就是 Generator 函数的语法糖。例有一个Generator依次读取两个文件;
var fs = require('fs')
const readeFile = function(filename){
return new Promise(function(resolve, reject){
fs.readFile(fileName, function(error, data){
if (error) reject(error);
resolve(data)
})
})
}
const gen = function *(){
var f1 = yield readFile('/f1');
var f2 = yield readFile('/f2');
console.log(f1);
console.log(f2);
}
写成async就是这样:
const asyncFile = async function(){
var f1 = await readFile('/f1')
var f2 = await readFile('/f2')
console.log(f1);
console.log(f2);
}
async 函数的优点
- async 和 await,比起星号和 yield,语义更清楚。async 表示函数里有异步操作,await 表示后面的表达式需要等待结果。
- yield 命令后面只能是 Thunk 函数或 Promise 对象,而await 命令后面可以跟Promise对象也可以是对象、数组、数字、字符串这些(但是等同于同步操作)。
async函数的用法
async 函数返回一个 Promise 对象,可以使用 then 方法指定下一步操作。
当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。
async function getByName(name){
const name = await queryName(name)
return name
}
getByName('qqh').then(function(res){
console.log(res)
})
上面的例子中,前面声明了一个异步函数getByName,表示该函数内部有异步操作,调用函数时,会返回一个Promise对象。下面是一个指定多少毫秒输出的例子;
async function timeout(ms){
return new Promise(function(resolve){
setTimeout(resolve, ms)
})
}
async function print(value, ms){
await timeout(ms)
console.log(value, ms)
}
print('hello word', 2000)
上面指定2秒后,输出一个 ‘hello word, 2000’,可以看到在执行print函数的时候会先返回一个Promise,再等待await后面的timeout执行完后,再往下执行。
函数语法
async函数内部return语句返回的值,会成为then方法回调函数的参数
async function getName(){
return 'qqh'
}
getName().then(v => console.log(v)) //qqh
await命令后面如果不是一个promise对象,会被转成一个立即resolve的 Promise 对象
async function getName() {
return await 'qqh';
}
getName().then(v => console.log(v)) // qqh
await命令后面的 Promise 对象如果变为reject状态,则reject的参数会被catch方法的回调函数接收到
async function getName() {
await Promise.reject('取不到名字了');
}
getName()
.then(v => console.log(v))
.catch(e => console.log(e)) // 取不到名字了
注意事项
(1)多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发
const name = await queryName()
const body = await queryBody()
上面的代码中,queryName和queryBody是两个独立的异步操作,queryName完成后才会执行queryBody;
这样比较耗时了,我们完全可以让他们同时执行;
// 写法一
let [name, body] = await Promise.all([queryName(), queryBody()]);
// 写法二
let namePro = queryName();
let bodyPro = queryBody();
let name = await namePro;
let body = await bodyPro;
上面两种写法,queryName和queryBody都是同时触发,这样就可以缩短程序的执行时间。
(2)await 命令只能用在 async 函数之中,如果用在普通函数,就会报错。
async function getList(db){
var data = [{id:1}, {id:2}, {id:3}]
//会报错
data.forEach(v=>{
await db.post(v)
})
}
async function getList(db){
var data = [{id:1}, {id:2}, {id:3}]
//得到的结果会不正确
data.forEach(async v=>{
await db.post(v)
})
}
要解决上面代码的问题,我们可以采用for…of循环;
async function getList(db){
var data = [{id:1}, {id:2}, {id:3}]
//得到的结果会不正确
for(let v of data){
await db.post(v)
}
}
如果确实希望多个请求并发执行,可以使用 Promise.all 方法。
var db = {
post: function (v) {
return new Promise((resolve, reject)=>{
setTimeout(function () {
resolve('post success id:' + v.id)
}, 2000)
})
}
}
async function getList(db){
var data = [{id:1}, {id:2}, {id:3}]
var promises = data.map(v=>{ return db.post(v) })
var res = await Promise.all(promises)
return res
}
getList(db).then(v=>{
console.log(v)
//['post success id:1', 'post success id:2', 'post success id:3']
})