async和await已经出来很久了,具体什么用法也就不说了,写这篇文章的目的就是:最近我疯狂的想要了解async和await的实现方法,人在一个月里总有那么三两天想要打打渔,晒晒网,所里了解以后就想记录下来
Generator生成器
其实我们都多多少少知道,async/await其实就是Generator的语法糖,他的底层就是Generator和Promise
Generator的用法
function* gen(){
yield 'hello';
yield 'world';
yield 'ends';
}
let g1 = gen()
console.log(g1) // {}
console.log(g1.next()) // {value: 'hello', done: false}
console.log(g1.next()) // {value: 'world', done: false}
console.log(g1.next()) // {value: 'ends', done: false}
console.log(g1.next()) // {value: 'undefined', done: true}
和普通的函数的区别是:第一次调用的时候是不会立即执行的,而是指向遍历器对象,继续往下执行需要调用 next() 方法,一直执行到下一个 yield 或者 return 的地方,每次执行会返回一个对象,对象里包含 value(此次执行得到的结果,如果执行完毕就会返回undefined) 以及 done(执行的状态,如果已经执行完,就会变成true)
为什么说async/await其实就是Generator的语法糖
下面看一个例子
function getName() {
return new Promise((rs, rj) => {
rs('啧啧啧')
})
}
function getAge() {
return new Promise((rs, rj) => {
rs('22')
})
}
- 使用async/await执行
async function getResult() {
const name = await getName();
const age = await getAge();
return (name + age + '岁了'); // '啧啧啧22岁了'
}
getResult()
- 使用yield
function* getResultYield() {
const name = yield getName();
const age = yield getAge();
console.log('name', name)
console.log('age', age);
console.log(name + age + '岁了')
}
let genResult = getResultYield();
console.log('genResult', genResult);
console.log(genResult.next());
console.log(genResult.next());
console.log(genResult.next());
console.log(genResult.next());
我们会发现,其实这两中写法的区别就是把 async 换成了 * , 把await换成了yield,只不过除了这一点,还有就是我们需要自己执行 next() ,这就告诉我们,async里除了 Generator ,还需要一个 内置执行器 ,就是说让他自己执行 next()
自己实现一下吧
function* getAsyncYield() {
const name = yield getName();
const age = yield getAge();
return (name + age + '岁了')
}
testAsync(getAsyncYield)
- 根据上边的<使用yield>
function testAsync(funName) {
// 根据上边的<let genResult = getResultYield()>得知,我们需要先得到手动的指向遍历器对象
let genAsync = funName();
return new Promise((rs, rj) => {
function step(value) {
let genItem = genAsync.next(value);
console.log('genItem', genItem)
if(genItem.done) {
return rs(genItem.value)
}
return Promise.resolve(genItem.value).then(res => {
console.log('res----', res)
// rs(res)
step(res)
})
}
step()
})
}
- 在打印genItem的地方,在done为false的时候打印的都是 {value: Promise, done: false},这是因为 getName 和 getAge 返回的都是Promise,所以在done为false的时候,需要用Promise获取到value的值,并传递到 next() 方法中返回
最后扒了一下编译完的async和await
<!--用到async/await的代码-->
async onLoad (option) {
this.wxCode = await checkinService.wxLogin()
const toUrl = option.toUrl ? decodeURIComponent(option.toUrl) : ''
this.toUrl = toUrl
},
<!--编译完的代码-->
onLoad: function () {
var _onLoad = _asyncToGenerator( /*#__PURE__*/_regenerator.default.mark(function _callee(option) {
var toUrl;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
uni.showLoading({
title: '加载中',
mask: true
});
uni.removeStorageSync('user_token');
uni.removeStorageSync('userInformation');
this.$store.dispatch('currentLoginState', false);
_context.next = 6;
return _checkin.default.wxLogin();
case 6:
this.wxCode = _context.sent;
toUrl = option.toUrl ? decodeURIComponent(option.toUrl) : '';
this.toUrl = toUrl;
case 9:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
function onLoad(_x) {
return _onLoad.apply(this, arguments);
}
return onLoad;
}()
其实我觉得重要的,和async/await有关系的只有一个 _asyncToGenerator
function _asyncToGenerator(fn) {
return function () {
var self = this, args = arguments;
return new Promise(function (resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
其实感觉自己写的大体上差不多,没做容错,不够完整
目前只能写到这里了,要是有啥写的不对还请指出,谢谢
还发现一个之前没注意的问题<async和await也支持异步并行>
function setA(){
return new Promise((resolve)=>{
setTimeout(()=>{
console.log('aaa');
resolve();
},3000)
})
}
function setB(){
return new Promise((resolve)=>{
setTimeout(()=>{
console.log('bbb');
resolve();
},3000)
})
}
async function testAsync(){
// 异步 --> 等待6s
// let a = await setA();
// let b = await setB();
// 改成同步 --> 只等待3s
// let a = setA();
// let b = setB();
// await a;
// await b;
// console.log('all done');
// 同步2
// Promise.all([setA(),setB()]).then(()=>{console.log('all done')})
return '啧啧啧'
}
testAsync()
参考: 《async 函数的含义和用法》