async是什么
是js异步编程规范,结合await实现异步执行结果等待,将异步拥有同步代码的能力,其实底层就是一个generator生成器的语法糖。
原理
在编码的时候,会经常使用到async或者Promise,比如获取某个列表数据,两者代码如下:
// async
async function fn1() {
let res = await getList();
return res;
}
// promise
function fn2() {
return new Promise((resolve,reject)=>{
getList().then(res=>{
resolve(res);
});
});
}
fn1() // 返回的是一个promise对象
从上面代码执行,可以知道async返回的是一个Promise对象,其原理通过Promise实现。await又是如何能等待其后面的代码执行呢?ES6有generator生成器的yield可以代码暂停,调用next方法执行到下一个yield。代码如下:
// 定义生成器函数
function* gen() {
let a = yield 1;
let b = yield 2;
let c = yield 3;
return a + b + c;
}
const gc = gen();
gc.next() // {value: 1, done: false}
gc.next(1) // {value: 2, done: false}
gc.next(2) // {value: 3, done: false}
gc.next(3) // {value: 6, done: true}
分析执行过程:
第一个next传参其实没有任何意义,只会执行第一个yield后面的1;
第二个next传入1,执行了 let a=和第二个yield后面的2,a=1,即next(1)参数1;
同理第三个next之后,b = 2,即next(2)参数2;
第四个next之后,c = 3,没有了yield控制,直接return,所以返回{value: 6, done: true},done为true标识已经结束。
如果后面继续next执行,得到的值是{value: undefined, done: true}
实现async
结合上面generator以及Promise的分析,可以通过generator迭代器来实现async、await原理
/**
* 通过generator函数来实现async、await
*/
// 判断是不是promise对象
const isPromise = (o) => typeof o === 'object' && o !== null && typeof o.then === 'function';
// 转换成promise对象
const rawPromise = (val) => isPromise(val) ? val : Promise.resolve(val);
// 实现async方法
// generatorFn生成器
function asyncDeferred(generatorFn) {
return function () {
// 生成器对象
const gen = generatorFn.call(this, ...arguments);
// 返回一个Promise对象
return new Promise((resolve, reject) => {
// 定义一个执行next迭代的递归函数
const runStep = function (preValue) {
let stpVlue;
try {
stpVlue = gen.next(preValue);
} catch (err) {
reject(err);
}
const { value, done } = stpVlue;
if (done) {
resolve(value);
} else {
rawPromise(value).then(res => {
runStep(res);
}, err => {
gen.throw(err);
reject(err);
});
}
}
try {
runStep();
} catch (err) {
reject(err);
}
});
}
}
// 定义生成器函数
function* gen() {
let a = yield 1;
let b = yield 2;
let c = yield 3;
return a + b + c;
}
// 返回一个async方法
let asyncPromise = asyncDeferred(gen);
// 执行结果
asyncPromise().then(res => {
console.log(res); // 这里输出6
}).then(v => {
console.log(v); // 这里输出undefined
})
注意实现:
1、所有结果必须以Promise对象返回,所以要有isPromise和rawPromise将一般返回值转换成Promise对象;
2、执行过程中还需要考虑异常错误情况,try-catch用来捕获异常。
有不妥之处,望江湖大佬指正~