ES6 await

async函数

含义

他就是Generator函数的语法糖,generator函数读取两个文件

const fs=require('fs');
const readFile=function(fileName){
	return new Promise(function(resolve,reject){
		fs.readFile(fileName,function(error,data){
			if(error) return reject(error);
			resolve(data);
			});
		});
};

const gen=function* (){
	const f1=yield readFile('/etc/fstab');
	const f2=yield readFile('/etc/shells');
	console.log(f1.toString());
	console.log(f2.toString());
}

上面的代码gen写成async就是这样

const asyncReadFile=async function (){
	const f1=await readFile('/etc/fstab');
	const f2=await readFile('/etc/shells');
	console.log(f1.toString());
	console.log(f2.toString());
} 

async对Generator函数的改进,体现在一下四点

  1. 内置执行器 执行与普通函数一样
  2. 更好的语义
  3. 更广的适用性
  4. 返回值是Promise

基本用法

async function getStockPriceByName(name){
	const symbol=await getStockSymbol(name);
	const stockPrice=await getStockPrice(symbol);
	return stockPrice;
}//返回一个promise
getStockPriceByName('goog').then(function(result){
	console.log(result);
	});

另一个例子

function timeout(ms){
	return new Promise((resolve)=>{
		setTimeout(resolve,ms);
		});
}
async function asyncPrint(value,ms){
	await timeout(ms);
	console.log(value);
}
asyncPrint('hello world', 50);

上面代码50ms输出helloworld
由于saync函数返回的是Promise对象,可以作为await命令的参数,所以,上面的例子也可以写成下面形式

async function timeout(ms){
	await new Promise((resolve)=>{
		setTimeout(resolve,ms);
		});
}
async function asyncPrint(value,ms){
	await timeout(ms);
	console.log(value);
}
asyncPrint('hello world',50);

async函数有多种使用形式

//函数声明
async function foo(){}
//函数表达式
const foo = async function() {};
//对象的方法
let obj={ async foo(){} };
obj.foo().then(...)

//Class的方法
class Storage{
	constructor(){
		this.cachePromise = caches.open('avatars');
	}
	async getAvatar(name){
		const cache=await this.cachePromise;
		return cache.match(`/avatars/${name}.jpg`);
	}
}
const storage=new Storage();
storage.getAvatar('jake').then(...);

//箭头函数
const foo = async ()=>{};

语法

async函数语法总体比较简单,难点是错误处理机制

返回Promise对象

函数内的返回值成为then方法回调函数的参数。

async function f(){
	return "hello world";
}
f().then(v => console.log(v));//hello world

async函数内部抛出的错误会导致返回的Promise对象变为reject状态,抛出的错误对象会被catch方法回调函数接收

async function f(){
	throw new Error('出错了');
}
f().then(
	v=>console.log(v),
	e=>console.log(e)
	)
	//Error: 出错了

Promise对象的状态变化

async函数返回的Promise对象,必须等await命令后面的Promise对象执行完,才会发生状态改变。

async function getTitle(url){
	let response=await fetch(url);
	let html=await response.text();
	return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle("xxxxxx").then(console.log);

上述getTitle内的操作全部完成,才会执行console.log

await命令

await命令后面是一个Promise对象,返回该对象的结果,如果不是Promise对象返回对应的值。

async function f(){
	return await 123;
}
f().then(v => console.log(v));

另一种情况返回thenable对象,await会将其等同Promise对象

class Sleep{
	constructor(timeout){
		this.timeout=timeout;
	}
	then(resolve,rejcet){
		const startTime=Date.now();
		setTimeout(
		()=>resolve(Date.now()-startTime),
		this.timeout;
			);
	}
}
(async ()=>{
	const sleepTime = await new Sleep(1000);
	console.log(sleepTime);
	})

上面代码await命令后面是Sleep对象实例,定义了then,await将其视为Promise处理。
实现简单休眠

function sleep(interval){
	return new Promise(resolve=>{
		setTimeout(resolve,interval);
		})
}
//用法
async function one2FiveInAsync(){
	for(let i=1;i<=5;i++){
		console.log(i);
		await sleep(1000);
	}
}

one2FiveInAsync();

await命令后面Promise对象如果变为reject状态,则reject参数会被catch方法回调函数接收

async function f(){
	await Promise.reject("出错了");
}
f()
.then(v=>console.log(v))
.catch(e=>console.log(e));
//出错了

注意上面代码await没有return,但是reject方法的参数依然传入了catch方法的回调函数。
任何一个await语句后面的Promise对象变为reject状态,整个async函数都会中断。

async function f(){
	await Promise.reject('出错了');
	await Promise.resolve('hello world');//不会执行
}

第二行代码不会执行,因为await语句状态变成了reject
如果需要即使前面一个异步操作失败,也不要中断后面的异步操作,可以将await放在try…catch结构里面。

async function f(){
	try{
		await Promise.reject('出错了');
	}catch(e){

	}
	return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
//hello world

另一种方法是await后面的Promise对象再跟一个catch方法,处理前面可能出现的错误。

async function f(){
	await Promise.reject('出错了')
	.catch(e => console.log(e));
	return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v));
//出错了 
//hello world

错误处理

如果await后面的异步操作出错,等同于async函数返回的Promise对象被reject

async function f(){
	await new Promise(function(resolve,reject){
		throw new Error('出错了');
		});
}
f()
.then(v => console.log(v))
.catch(e => console.log(e));

上面代码async函数f执行后,await后面的Promise对象抛出一个错误对象,导致catch方法回调函数被调用,参数为抛出的错误对象
防止出错的方法,也可以将其放在try…catch中

async function f(){
	try{
		await new Promise(function(resolve,reject){
			throw new Error('出错了');
			});
	}catch(e){

	}
	return await('hello world');
}

如果有多个await命令,可以统一放在try…catch中

async function main(){
	try{
		const val1=await firstStep();
		const val2 = await secondStep(val1);
    const val3 = await thirdStep(val1, val2);

    console.log('Final: ', val3);
	}catch (err) {
    console.error(err);
  }
}

下面例子使用try…catch结构 实现多次重复尝试

const superagent = require('superagent');
const NUM_RETRIES = 3;

async function test() {
  let i;
  for (i = 0; i < NUM_RETRIES; ++i) {
    try {
      await superagent.get('http://google.com/this-throws-an-error');
      break;
    } catch(err) {}
  }
  console.log(i); // 3
}

test();

上面代码,成功跳出,失败catch捕捉,下一轮

使用注意点

同时触发

let [foo,bar]=await Promise.all([getFoo(),getBar()]);//1
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;//2

并发执行

async function dbFuc(db){
	let docs=[{},{},{}];
	let promises=docs.map((doc)=>db.post())

	let results=await Promise.all(promises);
	console.log(results);
}

async函数保留运行栈

const a = async()=>{
	await b();
	c();
}

async 函数实现原理

将Generator和自执行器包装在一个函数里

async function fn(args){

}
//等同于
function fn(args){
	return spawn(function* (){

		})
}

具体实现

function spawn(genF){
	return new Promise(function(resolve,reject){
		const gen=genF();
		function step(nextF){
			let next;
			try{
				next=nextF();
			}catch(e){
				return reject(e);
			}
			if(next.done){
				return resolve(next.value);
			}
			Promise.resolve(next.value).then(function(v){
				step(function(){ return gen.next(v); })
				},function(e){
					step(function(){ return gen.throw(e); })
					});
		}
		step(function(){ return gen.next(undefined); });
		})
}

与其他异步比较

并发远程请求

async function logInOrder(urls){
	const textPromises=urls.map(async url->{
		const response = await fetch(url);
		return response.text();
		});
	for(const textPromise of textPromises){
		console.log(await textPromise);
	}
}
ES6中的async和await是用于处理异步操作的关键字。async关键字用于声明一个函数是异步的,而await关键字用于等待一个异步任务执行完成。 通过使用async和await,我们可以以同步的方式编写异步代码,使得代码更加清晰和易读。 使用async关键字声明的函数会返回一个Promise对象。在函数内部,我们可以使用await关键字来等待一个异步任务执行完成,而不需要使用回调函数或者Promise的then方法。当await关键字等待一个异步任务时,它会暂停函数的执行,并且等待异步任务完成后继续执行函数。 async和await的使用可以大大简化异步代码的编写,使得代码更易于理解和维护。它们是ES6中非常有用的特性,被广泛应用于JavaScript开发中。 引用: 目录 ES6的async和await关键字1、初步了解2、async关键字3、await关键字4、深入讲解async和await。 :主要介绍了详解ES6之async await 同步/异步方案,本文以最简明的方式来疏通 async await,有兴趣的可以了解下。 :我们先从字面意思来理解这两个关键字,async是asynchronous(异步)的简写,而await可以认为是async wait的简写。所以async可以理解为用于声明一个函数是异步的,而await用于等待一个异步任务执行完成。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [详解ES6的async和await关键字](https://blog.csdn.net/ldjgood/article/details/123696983)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [详解ES6之async+await 同步/异步方案](https://download.csdn.net/download/weixin_38746166/12772472)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值