async函数学习笔记
含义
async函数是什么?一句话,它就是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');
cosnt f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
}
一比较就会发现,async函数就是将Generator函数的星号替换成async,将yield替换成await,仅此而已。
async函数对Generator函数的改进,体现在以下四点。
(1)内置执行器
Generator函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。
asyncReadFile()
上面的代码调用了asyncReadFile函数,然后它就会自动执行,输出最后结果。这完全不像Generator函数,需要调用next方法,或则用co模块,才能真正执行,得到最后结果。
(2)更好的语义
async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
(3)更广的适用性
co模块约定,yield命令后面只能是Thunk函数或Promise对象,而async函数的await命令后面,可以是Promise对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。
(4)返回值是Promise
async函数的返回值是Promise对象,这比Generator函数的返回值Iterator对象方便多了。你可以用then方法指定下一步的操作。
进一步说,async函数完全可以看作多个异步操作,包装成的一个Promise对象,而await命令就是内部then命令的语法糖。
基本用法
async函数返回一个Promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
下面是一个例子。
async function getStockPriceByName(name){
const symbol = await getStockSymbol(name);
const stockPrice = await getStockPrice(symbol);
return stockPrice;
}
getStockPriceByName('goog').then(function(result){
console.log(result);
})
上面代码是一个获取股票报价的函数,函数前面的async关键字,表明该函数内部有异步操作。调用该函数时,会立即返回一个Promise对象。
下面是另一个例子,指定多少毫秒后输出一个值。
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);
由于async函数返回的是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', 5000);
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()=>{};
返回Promise对象
async函数返回一个Promise对象。
async函数内部return语句返回的值,会成为then方法回调函数的参数。
async function f(){
return 'hello world';
}
f().then(v=>console.log(v))//'hello world'
上面代码中,函数f内部return命令返回的值,会被then方法回调函数接收到。
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对象执行完,才会发生状态改变,除非遇到return语句或则抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
async function getTitle(url) {
let response = await fetch(url);
let html = await response.text();
return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log)
上面代码中,函数getTitle内部有三个操作:抓取网页、取出文本、匹配页面标题。只有这三个操作全部完成,才会执行then方法里面的console.log()
await命令
正常情况下,await命令后面是一个Promise对象,返回该对象的结果。如果不是Promsie对象,就直接返回对应的值。
async function f(){
//等同于123;
return await 123;
}
f().then(v=>console.log(v))
上面代码中,await命令的参数是数值123,这时等同于return 123.
另一种情况是,await命令后面是一个thenable对象(即定义then方法的对象),那么await会将其等同于Promise对象。
class Sleep{
constructor(timeout){
this.timeout = timeout;
}
then(resolve,reject){
const startTime = Date.now();
setTimeout(
()=>resolve(Date.now()-startTime)
this.timeout
)
}
}
(async()=>{
const actualTime = await new Sleep(1000);
console.log(actualTime);
})();
上面代码中,await命令后面是一个Sleep对象的实例。这个实例不是Promise对象,但是因为定义了then方法,await会将其视为Promise处理。
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前面加上return,效果是一样的。
任何一个await语句后面的Promise对象变为reject状态,那么整个async函数都会中断执行。
有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个await放在try...catch结构里面,这样不管这个异步操作是否成功,第二个await都会执行。
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。防止出错的方法,也是将其放在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++){
await superagent.get('http://goole.com/this-throws-an-error');
break;
}catch(err){}
console.log(i);//3
}
test();
上面代码中,如果await操作成功,就会使用break语句退出循环;如果失败,会被catch语句捕捉,然后进入下一轮循环。
来源:https://segmentfault.com/a/1190000017469670
async函数学习笔记的更多相关文章
- async 函数学习笔记
async函数就是Generator函数的语法糖. var fs = require('fs'); var readFile = function (fileName) { return new Pr ...
- async 函数--学习笔记一
含义: ES2017 标准引入了 async 函数,使得异步操作变得更加方便.async 函数是什么?一句话,它就是 Generator 函数的语法糖. 前文有一个 Generator 函数,依次读取 ...
- C# async await 学习笔记2
C# async await 学习笔记1(http://www.cnblogs.com/siso/p/3691059.html) 提到了ThreadId是一样的,突然想到在WinForm中,非UI线程 ...
- C++学习基础十六-- 函数学习笔记
C++ Primer 第七章-函数学习笔记 一步一个脚印.循序渐进的学习. 一.参数传递 每次调用函数时,都会重新创建函数所有的形参,此时所传递的实参将会初始化对应的形参. 「如果形参是非引用类型,则 ...
- C#同步,异步的理解,包括5.0中await和async(学习笔记)
之前在工作中一直用的是同步线程,就是先进入画面的load事件,然后在里面进行数据库调用的处理.后面又遇到了公司软件中一些比较古老的代码,一开始在那块古老代码中增加机能的时候,我想用到数据库的数据给画面 ...
- async/await学习笔记
async/await 的目的是简化使用 promises 的写法. 让我们来看看下面的例子: // 一个标准的 JavaScript 函数 function getNumber1() { r ...
- contiki-main.c 中的process系列函数学习笔记 <contiki学习笔记之六>
说明:本文依然依赖于 contiki/platform/native/contiki-main.c 文件. ---------------------------------------------- ...
- Swift2.0 函数学习笔记
最近又有点忙,忙着找工作,忙着适应这个新环境.现在好了,上班两周周了,也适应过来了,又有时间安安静静的就行我们前面的学习了.今天这篇笔记,记录的就是函数的使用.下面这些代码基本上是理清楚了函数的额使用 ...
- MYSQL存储过程和函数学习笔记
学至Tarena金牌讲师,金色晨曦科技公司技术总监沙利穆课程笔记的综合. 1. 什么是存储过程和函数 将SQL语句放入一个集合里,然后直接调用存储过程和函数来执行已经定义好的SQL语句,通过存储过程和 ...
随机推荐
- 微信小程序 使用HMACSHA1和md5为登陆注册报文添加指纹验证签名
对接口请求报文作指纹验证签名相信在开发中经常碰到, 这次在与java后端一起开发小程序时,就碰到需求对登陆注册请求报文添加指纹验证签名来防止信息被修改 先来看下我们与后端定制签名规则 2.4. 签名规 ...
- Codeforces Gym101502 J-取数博弈
还有J题,J题自己并不是,套的板子,大家写的都一样,因为大家都是套板子过的,贴一下代码,等学会了写一篇博客... J.Boxes Game 代码: 1 //J. Boxes Game-取数博弈-不会, ...
- Jython中文乱码问题
最近,在项目中需要用到Java代用Python的代码,并且需要传参数,因此选用了Jython包,但是,如果在调用python脚本时,出现了中文乱码的现象.代码如下: PythonInterpreter ...
- 【CSS】获取元素的z-index值以及各种值的意义
js可以获取其元素的z-index值: $("document").ready(function(){ var a = $('.row').css('z-index'); aler ...
- WCF中常用的binding方式 z
WCF中常用的binding方式: BasicHttpBinding: 用于把 WCF 服务当作 ASMX Web 服务.用于兼容旧的Web ASMX 服务. WSHttpBinding: 比 Bas ...
- Apache和IIS共享80端口的四个设置方法
方法一:IIS5,多IP下共存,IIS为192.168.0.1,apache为192.168.0.2c:\Inetpub\Adminscriptscscript adsutil.vbs set w3s ...
- [Javascript] Await a JavaScript Promise in an async Function with the await Operator
The await operator is used to wait for a promise to settle. It pauses the execution of an async func ...
- css3 - 基本选择器
有人说类选择器最好不要超过三层,其实我也是这样认为的,不是吗? 选择器分为四大类 标签.全选(相对于子类继承了0.1).类.ID 权值分别是:1->0.1->10->100(权值可叠 ...
- Eclipse 安装(Oxygen版本)
Eclipse 安装(Oxygen版本) Eclipse 最新版本 Eclipse Neon,这个首次鼓励用户使用 Eclipse Installer 来做安装,这是一种由Eclipse Oomph提 ...
- Solaris 系统启动与关闭
忘掉root密码 更改内核参数后,重启进不了系统 复制---进入单用户模式----恢复文件 系统突然死机,如何尽量减少数据丢失 Sync 同步命令.将内存内容输入到硬盘,相当于保存文档. Unix ...