爱是天时地利的迷信---《原来你也在这里》
嗨,宝宝们,emmm…… 我一说“宝宝们”这三个字就想起一个男生……
1.async的含义
async函数其实是Geneator函数的语法糖。
async函数对Generator函数的改进:
(1)内置执行器
Generator函数的执行必须靠执行器,所以才有co模块,而async函数自带执行器。
(2)更好的语义
async和await,相比于*和yield语义更清楚。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
(3)更广的适用性
co模块预定,yield命令后面只能是Thunk函数或Promise对象。而async函数的await命令后面可以是Promise对象和原始类型的值(数值、字符串和布尔值,这时候自动转成立即resolve的Promise对象)
(4)返回值是Promise
async函数的返回值是Promise对象,可以用then方法指定下一步的操作。async函数可以看做多个异步操作,包装成一个Promise对象,await命令就是内部then命令的语法糖。
2.async用法
async函数返回一个Promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体后面的语句。
例:
async function getStockPriceByName(name){
const symbol = await getStockSymbol(name);
const stockPrice = await getStockPricd(symbol);
return stockPrice;
}
getStockPriceByName('goog').then(function(res){
console.log(res);
})
函数前面的async关键字,表明该函数内部有异步操作。调用该函数时,会立即返回一个Promise对象。
2.async语法
返回Promise对象
async函数返回一个Promise对象。
async函数内部return语句返回的值,会成为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)
)
Promise对象的状态变化
async函数返回的Promise对象,必须等到内部所有的await命令后面的Promise对象执行完,才会发生状态变化,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行执行then方法指定的回调函数。
await命令
正常情况下,await命令后面是一个Promise对象,返回该对象的结果。如果不是Promise对象,就直接返回对应的值。
另外,await命令后面是一个thenable对象(定义了then方法的对象),那么await会将其等同于Promise对象。
任何一个await语句后面的Promise对象变为reject状态,那么整个async函数都会中断执行。
async function f(){
await Promise.reject('出错了');
await Promise.resolve('hello world');
}
上面代码中,第二个await语句是不会执行的,因为第一个await语句变成了reject。
可是如果我想要第二个await语句执行呢?
async function f(){
try{
await Promise.reject('出错了');
}catch{}
return await Promise.resolve('hello world');
}
还可以
async function f(){
await Promise.reject('出错了')
.catch(e => console.log(e))
return await Promise.resolve('hello world');
}
错误处理
await后面的异步操作出错,等于async函数返回的Promise对象被reject。
注意事项:
1.await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。
async function fun(){
try{
await returnPromise();
}catch(err){
console.log(err)
}
}
// 或者
async function fun1(){
await returnPromise()
.catch(function(err){
console.log(err)
})
}
2.多个await命令后面的异步操作,如果不存在继发关系,最好让他们同时触发
let foo = await getFoo();
let bar = await getBar();
getFoo和getBar是两个独立的异步操作,被写成激发关系比较耗时,所以可以让他们同时触发,方法如下:
let [foo, bar] = await Promise.all([getFoo(),getBar()]);
// 或者
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
3. await命令只能用在async函数之中,若用在普通函数中会报错。
4. async函数可以保留运行堆栈。
const a =()=>{
b().then(()=>c{});
}
以上,当b运行时,a不会中断,而是继续执行。等到b()运行结束,可能a早就运行结束,b所在的上下文环境已经消失。如果b或c报错,错误堆栈将不包括a。
const a = async()=>{
await b();
c();
}
b运行的时候,a暂停运行,上下文环境都保存着,一旦b或c报错,错误堆栈将包括a。
愿我们有能力不向生活缴械投降---Lin