async和Generator是一对好基友,且async是主动型

Posted 桃子叔叔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了async和Generator是一对好基友,且async是主动型相关的知识,希望对你有一定的参考价值。

async 函数是ES7标准引入的

一、什么是async函数

1、async 让异步代码变得像同步代码一样

  • 返回一个promise对象
  • promise对象的结果由async函数执行结果的返回值决定

2、Generator 的好基友(语法糖)

虽然说async函数是Generator函数的好基友,但是一点也不省油,首先让我们看一下它们的区别
在这里插入图片描述

2.1 好基友的不同点

通过下面两段代码可以发现,async函数就是将Generator函数的星号*替换成async,将yield替换成await

// Generator函数:
function * gen(){
	let users = yield getUsers()
	let orders = yield getOrders()
	let goods = yield getGoods()
}

let iterator = gen()
iterator.next()

Generator函数标志是星号*和yield,通过next()来一步步执行yield操作。

可以说Generator函数是被动型,不喜欢自己动,喜欢被步步紧逼。
但是async函数就是主动型选手了。

const p = new Promise((resolve, reject)=> {
    resolve('用户数据')
})

var main = async function () {
    try {
        let result = await p;
        console.log(result) // 用户数据
    } catch (error) {
        console.log(e)
    }   
    // 通过try...catch捕获reject的返回值
}
main()

async函数自带执行器,一次调用,自动输出,这也是大家更喜欢async函数的原因。

2.2 async函数对好基友Generator进行了改进
  1. 第一个就是前面说的,async是主动的,自带执行器,而Generator喜欢被动,除非搭配co模块
  2. async语义更好,async表示有异步操作,await表示屁股后面紧跟的表达式需要结果
  3. async适用性更广,可谓人见人爱
  4. async返回值是Promise对象,可用then指定下一步操作,用起来很方便

一句话总结,async函数主动型、人见人爱、好用,接下来就详细说一下async的用法。

二、async函数用法

1、async基本语法

async function fn() {
// 如果函数返回的结果不是promise对象,async返回的结果就是成功的promise对象
// 如果函数返回的结果是一个promise对象,则根据函数内promise的结果判断
// 例如下面的promise函数
    return new Promise((resolve, reject)=> {
        resolve('成功的数据')
        // reject('失败的数据')
    })
}
const result = fn()

result.then((value)=> {
    console.log(value) // '成功的数据' 如果函数体内的promise返回resolve则走这里
}, (reason)=> {
    console.log(reason)// '失败的数据' 如果函数体内的promise返回reject则走这里
})

2、await语法

2.1 await必须写在async函数中
2.2 await右侧的表达式一般为promise对象
2.3 await返回的是promise成功的值
2.4 await的promise失败了,就会抛出异常,需要通过try…catch捕获异常
const p = new Promise((resolve, reject)=> {
    resolve('用户数据')
})

async function main() {
    try {
        let result = await p;
        console.log(result) // 用户数据
    } catch (error) {
        console.log(e)
    }   
    // 通过try...catch捕获reject的返回值
}

2.5 async返回的Promise对象必须等到内部所有await命令后的Promise对象执行完才发生状态改变,即执行then方法指定的回调函数,除非遇到return或抛出错误。
2.6 只要一个await语句后面的promise变成reject,那个整个async函数都会中断执行
async function f() {
    await Promise.reject('出错了')
    await Promise.resolve('这里不会执行')
}

上面代码中的第二行不会执行,因为第一个await语句状态变成了reject。

有时我们希望前一个promise中断不影响后面的await语句执行,这时需要将await放在try…catch语句中

async function f() {
    try {
        await Promise.reject('出错了')
    } catch (error) {}
    await Promise.resolve('这里不会执行')
}

另一种方法是将前面的await语句加上catch方法,处理前面可能出现的错误。

async function f() {
    await 
    Promise.reject('出错了')
    .catch(e=> console.log(e))
    await Promise.resolve('这里不会执行')
}

3、await实际应用

如果我们有三个登录权限需要去判断,只要命中其中一个就可以退出判断,不再进行其他判断,使用Promise和async实现:

let a = new Promise((resolve, reject)=>{
    let status = true
    // a权限逻辑判断代码----
    if (status) {
        resolve(status)
    } else {
        reject(status)
    }
})

let b = new Promise((resolve, reject)=>{
    let status = true
    // b权限逻辑判断代码----
    if (status) {
        resolve(status)
    } else {
        reject(status)
    }
})

let c = new Promise((resolve, reject)=>{
    let status = true
    // c权限逻辑判断代码----
    if (status) {
        resolve(status)
    } else {
        reject(status)
    }
})

let authList = [a, b, c]
let test = async function(){
    for(let auth of authList){
        try {
			await auth
            break
		} catch (error) {
			console.log(error)
		}
    }
}

在上面async代码中,如果await操作成功,则会使用break语句退出循环;如果失败,则会被catch语句捕捉,然后进入下一轮循环。

以上是关于async和Generator是一对好基友,且async是主动型的主要内容,如果未能解决你的问题,请参考以下文章

每天十分钟学好ES6--async和Generator是一对好基友

一对好基友,深度优先vs.广度优先搜索

算法相爱相杀好基友——数组与链表

01背包--小P寻宝记——粗心的基友

好基友,谈架构设计

BZOJ4155[Ipsc2015]Humble Captains 最小割+DP