async函数的基本用法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了async函数的基本用法相关的知识,希望对你有一定的参考价值。
参考技术A 1. async函数的基本形式//函数声明asyncfunction foo() //函数表达式const foo = asyncfunction () ;//对象的方法let obj = async foo() ;
obj.foo().then(...)//Class 的方法class Storage
constructor()
this.cachePromise = caches.open('avatars');
async getAvatar(name)
const cache = awaitthis.cachePromise;
returncache.match(`/avatars/$name.jpg`);
const storage =new Storage();
storage.getAvatar('jake').then(…);//箭头函数const foo = async () => ;
2. async函数的返回值总是一个Promise
无论async函数有无await操作,其总是返回一个Promise。
1. 没有显式return,相当于return Promise.resolve(undefined);
2. return非Promise的数据data,相当于return Promise.resolve(data);
3. return Promise, 会得到Promise对象本身
async总是返回Promise,因此,其后面可以直接调用then方法,
函数内部return返回的值,会成为then回调函数的参数
函数内部抛出的错误,会被then的第二个函数或catch方法捕获到
//正常返回值asyncfunction f()
retrun 'hello world';
f().then(v => console.log(v));//hello world//抛出错误asyncfunction f()
thrownewError('出错了');
f().then(
v => console.log(v),
e => console.log(e)//Error: 出错了)
3. await操作符的值
[rv] = await expression(expression可以是任何值,通常是一个promise)
expression是Promise,rv等于Promise兑现的值,若Promise被拒绝,则抛出异常,由catch捕获
expression是非Promise,会被转换为立即resolve的Promise,rv等于expression
await操作只能用在async函数中,否则会报错。
4. async就是generator和promise的语法糖
//generator写法vargen =function* ()
varf1 = yield readFile('/etc/fstab');
varf2 = yield readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
;//async写法varasyncReadFile = asyncfunction ()
varf1 = await readFile('/etc/fstab');
varf2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
;
async就是将 generator的 * 换成 async,将 yield 换成 await。
5. async对generator的改进
1. 内置执行器
Generator必须依靠执行器调用next方法来自动执行,例如co模块。而async函数自带执行器,可以自动执行。
2. 更好的语义
async和await分别表示异步和等待,语义更加明确
3. 适用性更强
co模块后面只能是Thunk函数或Promise对象,而await后面可以是Promise或基本数据类型(如:数字,字符串,布尔等)
4. 返回Promise,可以继续操作
async函数总是返回一个Promise对象,可以对其进行then调用,继续操作后面的数据,因此,
async函数完全可以看作是多个Promise合成一个Promise对象,而await命令就是内部的then调用。
6. async内部的并行调用
async配合await都是串行调用,但是若有并行调用,则应按照以下方式来写:
1. 变量分别接收Promise
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise();
let bar = await barPromise();
2. 使用Promise.all
let [foo,bar] = await Promise.all([getFoo(),getBar()]);
Promise.all这种写法有缺陷,一个调用报错,会终止,这个不太符合并行调用的初衷。
3. 使用多个async函数
实际上,一个async函数内部包含的调用应该是强相关的,没有依赖关系的函数调用不应该放在一个async函数中,分开来逻辑更清晰。
4. 并行执行的一些写法
1. 不能再内部非async function中使用await
asyncfunction dbFuc(db)
let docs = [, , ];
// 报错,forEach的function是非async,不能使用awaitdocs.forEach(function (doc)
await db.post(doc);
);
//这里不需要 asyncfunction dbFuc(db)
let docs = [, , ];
// 可能得到错误结果,这样调用也不能得到正确的结果docs.forEach(asyncfunction (doc)
await db.post(doc);
);
2. 循环调用await可以使用for循环或for of循环
//for ofasyncfunction dbFuc(db)
let docs = [, , ];
for (let doc of docs)
await db.post(doc);
//map + Promise.allasyncfunction dbFuc(db)
let docs = [, , ];
let promises = docs.map((doc) => db.post(doc));
let results = await Promise.all(promises);
console.log(results);
//map + for ofasyncfunction dbFuc(db)
let docs = [, , ];
let promises = docs.map((doc) => db.post(doc));
let results = [];
for (let promise of promises)
results.push(await promise);
console.log(results);
//for循环中去请求网页,若await操作成功,会break退出;若失败,会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();
7. async的错误处理
使用try...catch进行包裹,例如:
asyncfunction myFunction()
try
await somethingThatReturnsAPromise();
catch (err)
console.log(err);
如果仅仅对一部分错误进行处理或者忽略,可以局部的进行包裹,或者对单独的promise进行catch,例如:
asyncfunction myFunction()
await somethingThatReturnsAPromise().catch((err)=>
console.log(err);
)
async function myFunction()
try
await somethingThatReturnsAPromise();
catch(e)
await somethingElse();
Promise的错误处理,推荐用async + await来写:
// 存值createData(title, successBack, errorBack)
// 使用key保存数据 storage.save(
key: title,
data: 'true',
).then(successBack(), errorBack());
改写为
//存值async createData1(title, successBack, errorBack)
try
// 使用key保存数据 await storage.save(
key: title,
data: 'true',
);
successBack()
catch (e)
errorBack()
形式上更加清晰一些。
8. async函数的实现原理
async函数就是将执行器和Generator做为一个整体返回。
asyncfunction fn()//等同于function fn()
returnspawn(function* ()
)
spawn的实现
function spawn(genF)
/****
* 返回的是一个promise
*/returnnewPromise(function(resolve, reject)
vargen=genF();//运行Generator这个方法;/***
* 执行下一步的方法
* @param fn 一个调用Generator方法的next方法
*/function step(fn)
//如果有错误,则直接返回,不执行下面的awaittry
varnext=fn();
catch (e)
return reject(e)
//如果下面没有yield语句,即Generator的done是trueif(next.done)
return resolve(next.value);
Promise.resolve(next.value).then((val)=>
step(function()return gen.next(val) )
).catch((e)=>
step(function()returngen.throw(e) )
)
step(function ()
return gen.next();
)
);
参考自 async的基本用法 - 看风景就 - 博客园
C# 中的Async 和 Await 的用法详解
参考技术A 众所周知C#提供Async和Await关键字来实现异步编程。在本文中,我们将共同探讨并介绍什么是Async 和 Await,以及如何在C#中使用Async 和 Await。
同样本文的内容也大多是翻译的,只不过加上了自己的理解进行了相关知识点的补充,如果你认为自己的英文水平还不错,大可直接跳转到文章末尾查看原文链接进行阅读。
自从C# 5.0时代引入async和await关键字后,异步编程就变得流行起来。尤其在现在的.NET Core时代,如果你的代码中没有出现async或者await关键字,都会让人感觉到很奇怪。
想象一下当我们在处理UI和按钮单击时,我们需要运行一个长时间运行的方法,比如读取一个大文件或其他需要很长时间的任务,在这种情况下,整个应用程序必须等待这个长时间运行的任务完成才算完成整个任务。
换句话说,如果同步应用程序中的任何进程被阻塞,则整个应用程序将被阻塞,我们的应用程序将停止响应,直到整个任务完成。
在这种情况下,异步编程将非常有用。通过使用异步编程,应用程序可以继续进行不依赖于整个任务完成的其他工作。
在Async 和 await关键字的帮助下,使得异步编程变得很简单,而且我们将获得传统异步编程的所有好处。
假设我们分别使用了两种方法,即Method 1和Method 2,这两种方法不相互依赖,而Method 1需要很长时间才能完成它的任务。在同步编程中,它将执行第一个Method 1,并等待该方法的完成,然后执行Method 2。因此,这将是一个时间密集型的过程,即使这两种方法并不相互依赖。
我们可以使用简单的多线程编程并行运行所有方法,但是它会阻塞UI并等待完成所有任务。要解决这个问题,我们必须在传统编程中编写很多的代码,但是现在我们有了Async 和 await关键字,那么我们将通过书写很少的并且简洁的代码来解决这个问题。
此外,我们还将看到更多的示例,如果任何第三个方法(如Method 3)都依赖于Method 1,那么它将在Wait关键字的帮助下等待Method 1的完成。
Async 和 await是代码标记,它标记代码位置为任务完成后控件应该恢复的位置。
下面让我们举几个例子来更好进行理解吧
C#中Async 和 await关键字的示例
我们将采用控制台应用程序进行演示。
在这个例子中,我们将采取两个不相互依赖的方法。
在上面给出的代码中,Method 1和Method 2不相互依赖,我们是从主方法调用的。
在这里,我们可以清楚地看到,方法1和方法2并不是在等待对方完成。
输出
现在来看第二个例子,假设我们有Method 3,它依赖于Method 1
在本例中,Method 1将总长度作为整数值返回,我们在Method 3中以长度的形式传递一个参数,它来自Method 1。
在这里,在传递Method 3中的参数之前,我们必须使用AWAIT关键字,为此,我们必须使用调用方法中的async 关键字。
在控制台应用程序的Main方法中,因为不能使用async关键字而不能使用await 关键字,因为它会给出下面给出的错误。(但是如果你使用的是C#7.1及以上的方法是不会有问题的,因为C#7.1及以上的语法支持Mian方法前加async)
我们将创建一个新的方法,作为CallMethod,在这个方法中,我们将调用我们的所有方法,分别为Method 1、Method 2和Method 3。
在上面给出的代码中,Method 3需要一个参数,即Method 1的返回类型。在这里,await关键字对于等待Method 1任务的完成起着至关重要的作用。
输出
.NET Framework4.5中有一些支持API,Windows运行时包含支持异步编程的方法。
在Async 和 await关键字的帮助下,我们可以在实时项目中使用所有这些,以便更快地执行任务。
包含异步方法的API有HttpClient, SyndicationClient, StorageFile, StreamWriter, StreamReader, XmlReader, MediaCapture, BitmapEncoder, BitmapDecoder 等。
在本例中,我们将异步读取大型文本文件中的所有字符,并获取所有字符的总长度。
在上面给出的代码中,我们调用ReadFile方法来读取文本文件的内容,并获取文本文件中总字符的长度。
在sampleText.txt中,文件包含了太多的字符,因此读取所有字符需要很长时间。
在这里,我们使用异步编程从文件中读取所有内容,所以它不会等待从这个方法获得一个返回值并执行其他代码行,但是它必须等待下面给出的代码行,因为我们使用的是等待关键字,我们将对下面给出的代码行使用返回值。
随后,将按顺序执行其他代码行。
输出
在这里,我们必须了解非常重要的一点,如果我们没有使用await 关键字,那么该方法就作为一个同步方法。编译器将向我们显示警告,但不会显示任何错误。
像上面这种简单的方式一样,我们可以在C#代码中使用async 和await关键字来愉快的进行异步编程了。
最后的最后感谢大家的阅读!
以上是关于async函数的基本用法的主要内容,如果未能解决你的问题,请参考以下文章