generator的简单用法
今天研究了一下async函数的基本原理,和generator关系很大,首先看一下一个简单的generator函数
function *gen(){
yield 1
yield 2
yield 3
}
let g = gen()
for(let i = 0; i < 4; ++i){
console.log(g.next())
}
/**
* { value: 1, done: false }
* { value: 2, done: false }
* { value: 3, done: false }
* { value: undefined, done: true }
* /
generator函数运行到yield之前会停下,必须调用next才会向下运行,每次调用next会返回一个对象{value, done}, 并且next可以接收参数,作为上一个yield的返回值。
async的简单用法
贴代码
function promiseCreater(timeout){
return new Promise((resolve, reject) =>{
setTimeout(() =>{
console.log(timeout)
resolve(timeout)
}, timeout)
})
}
async function asyncTest(){
await promiseCreater(3000)
console.log("done")
await promiseCreater(2000)
console.log("done")
await promiseCreater(1000)
console.log("done")
}
asyncTest()
/***
* 3000
* done
* 2000
* done
* 1000
* done
* /
await在执行promise是阻塞代码,结果符合预期。
async与generator的联系
仔细看一下就会发现yield的阻塞作用很像await对promise的阻塞作用,也就是说通过generator函数自动调用next可以实现类似await的效果,promise执行结束时会调用then方法,可以将next放在then方法内实现自动执行。整理完思路下面简单实现一个自驱动的generator
function promiseCreater(timeout){
return new Promise((resolve, reject) =>{
setTimeout(() =>{
console.log(timeout)
resolve(timeout)
}, timeout)
})
}
function *gen(){
let a = yield promiseCreater(3000)
console.log(a)
let b = yield promiseCreater(2000)
console.log(b)
let c = yield promiseCreater(1000)
console.log(c)
}
function run(gen){
let g = gen()
function _next(val){
let res = g.next(val)
if(res.done){
return res.value
}
res.value.then((val) =>{
_next(val)
})
}
_next()
}
run(gen)
/***
* 3000
* 3000
* 2000
* 2000
* 1000
* 1000
* /
自驱动的原理就是then方法会在promise执行结束后执行,将next的调用放在then方法中就可以在promise结束后调用自动调用next,同时将val传递给next作为上一个yield的参数。
不过这个run方法很简陋,我们默认后面接的就是promise,而且没有相关的异常处理。
babel对async的处理
// run方法
function _asyncToGenerator(fn) {
return function() {
var self = this
var 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);
}
}
babel这边使用promise对函数进行了封装。异常处理和next都放在then的onFulfilled和onRejected中,根据promise的状态自动next或者捕获异常