浅谈async的实现原理

1,136 阅读2分钟

前言

已经有了个promise用来处理异步了,官方为何又要打造一个asyncawait来处理异步?

通常我们发接口请求,可能需要保证一个顺序,但是各个接口耗时又不同,因此我们需要将其捋成同步,比如下面模拟下用promise解决异步

function request (num) { 
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(num * 10)
        }, 1000)
    })
}

// const res1 = request(1)
// const res2 = request(res1)

request(1).then(res1 => {
    console.log(res1);
    request(res1).then(res2 => {
        console.log(res2);
    })
})

这里的情景是,两次接口请求,第二次需要依赖第一个返回的结果,写成这么一坨,形成的链式调用感觉很不优雅

好,现在看下async,await如何解决的

async function fn() {
    const res1 = await request(1) // await会把promise中的resolve值提取出来
    const res2 = await request(res1)
    console.log(res2);
}
fn()

我们再回顾下generator如何处理异步的,这里请求了三次

function* gen() { // generator处理异步
    const num1 = yield request(1)
    const num2 = yield request(num1)
    const num3 = yield request(num2)
    return num3
}

let g = gen()
const next1 = g.next()
next1.value.then(res1 => {
    console.log(res1);
    const next2 = g.next(res1)
    next2.value.then(res2 => {
        console.log(res2);
        const next3 = g.next(res2)
        next3.value.then(res3 => {
            console.log(res3);
        })
    })
})

generator处理异步更加不美观……

async,await的打造是基于promisegenerator

generator详解:详聊es6的Generator - 掘金 (juejin.cn)

async关键字会让函数默认返回一个promise对象

如果一个函数接收的参数还是个函数体,或者返回一个函数体,那么这个函数就被称之为高阶函数

所以这些函数都是高阶函数

async源码实现

async的核心还是generator,需要手动一直next调用,这里需要用上递归,其实co模块的源码就是下面的loop函数

function generatorToAsync(generatorFn) {
	const gen = generatorFn()
	return function () {
		return new Promise((resolve, reject) => {
			function loop (key, arg) {
				let res = null
				res = gen[key](arg)
				const { value, done } = res
				if (done) {
					return resolve(value)
				} else {
					Promise.resolve(value).then(res => { // promise直接交给resolve得话,promise中resolve的值会传过来
						loop('next', value)
					})
				}
			}
			loop('next')
		})
	}
}

最后

其实async,await相较于promise有个很大的缺点,他没有捕获错误的机制,所以需要自己人为去try,catch

async,await通过递归的方式实现了generator自动化执行next函数,等到donetrue,结束递归,拿到async函数最终的结果,其实这也是co模块的实现原理

如果你对春招感兴趣,可以加我的个人微信:Dolphin_Fung,我和我的小伙伴们有个面试群,可以进群讨论你面试过程中遇到的问题,我们一起解决

另外有不懂之处欢迎在评论区留言,如果觉得文章对你学习有所帮助,还请”点赞+评论+收藏“一键三连,感谢支持!