async函数的含义和用法

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 函数的优点

  1. async 和 await,比起星号和 yield,语义更清楚。async 表示函数里有异步操作,await 表示后面的表达式需要等待结果。
  2. 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']
})

猜你喜欢

转载自blog.csdn.net/qqhluckyi/article/details/83272404