作为ES7出现的语法,搭配promise使用,可以使得我们的异步编程更加方便和快捷,可是对于async/await背后的原理也是有必要理解的。
async/await
根据 MDN 定义,async 是一个通过异步执行并隐式返回 Promise 作为结果的函数。可以说async 是Generator函数的语法糖,并对Generator函数(这里不做过多解释)进行了改进。
Generator函数中的yield可以让代码执行暂停,并保留上下文,等待继续执行。
async 在内部其实是封装了Generator的执行器,做到了这一点。
看代码,下面是一个generator函数,它是如何异步执行的呢?
function* test() {
let response1 = yield fetch('https://blog.csdn.net/qcl006007') //返回promise对象
console.log('response1')
console.log(response1)
let response2 = yield fetch('https://blog.csdn.net/qcl006007') //返回promise对象
console.log('response2')
console.log(response2)
}
run(test);
在run函数中,就要用到执行器。
function run(gen){
//根据传入的生成器得到执行器 g
var g = gen();
// 定义内部函数 next
function next(data){
// 按照test 函数中的定义,得到的result是Promise
var result = g.next(data);
if (result.done) return result.value;
result.value.then(function(data){
next(data);
});
}
// 手动执行next函数,其实是开始执行test函数
next();
}
通过上面的代码可以想明白,async和await其实是将这背后的逻辑帮你做了而已,并且做了些扩展和优化:
相比于Generator 函数
- 内置执行器。Generator 函数的执行必须依靠执行器,而 async 函数自带执行器,无需手动执行 next() 方法。
- 语义明确。async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
- await 适用性更广。co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
- 保证函数的返回值是Promise。async 函数返回值是 Promise 对象,比 Generator 函数返回的 Iterator对象方便,可以直接使用 then() 方法进行调用,或者使用await函数获取结果。
关于async/await的执行顺序,会在下一篇继续写完。