最初JS的异步回调往往是通过把回调函数作为参数传入来实现的如:
async( callback )
自从es6的Promise函数出现以后,回调函数就能够通过链式结构来实现:
new Promise().then( callback )
而能够带来很大简化的还有使用生成器来实现异步函数,把异步逻辑写成同步的形式( fetch为js新增的请求函数,会发起请求并返回Promise对象 ):
function *test () {
yield fetch( url1 );
yield fetch( url2 );
yield fetch( url3 );
}
要使得 test 函数里的3个请求按异步顺序执行,需要自驱动函数,这里简单实现了一个:
/**
* 生成器自驱动函数
* @param {*} genFun
*/
function flow (genFun) {
let genInstance = genFun();
let result = {
done: false,
value: null,
};
/**
* 向前一步的意思
*/
function step () {
if (!result.done) {
result = genInstance.next( result.value );
// 如果迭代器的值是一个 promise 异步,那么等待回调下一步
if (result.value instanceof Promise) {
result.value.then( step );
}
// 其他的均视为同步代码,直接下一步
else {
step();
};
};
}
step();
}
完整的测试代码如下:
/**
* 生成器自驱动函数
* @param {*} genFun
*/
function flow (genFun) {
let genInstance = genFun();
let result = {
done: false,
value: null,
};
/**
* 向前一步的意思
*/
function step () {
if (!result.done) {
result = genInstance.next( result.value );
// 如果迭代器的值是一个 promise 异步,那么等待回调下一步
if (result.value instanceof Promise) {
result.value.then( step );
}
// 其他的均视为同步代码,直接下一步
else {
step();
};
};
}
step();
}
/**
* 测试用的生成器函数
*/
function *testGen () {
yield console.log( 1 );
yield new Promise(( resolve ) => {
console.log( "promise begin" );
setTimeout(() => {
console.log( "promise resolved" );
resolve();
}, 2000 );
});
yield *genChild();
yield console.log( 5 );
}
function *genChild () {
yield console.log( 3 );
yield new Promise(( resolve ) => {
console.log( "child promise begin" );
setTimeout(() => {
console.log( "child promise resolved" );
resolve();
}, 2000 );
});
yield console.log( 4 );
}
flow( testGen );
测试结果为,控制台输出:
其中flow函数里面的step函数在每次从 yield 获取结果之后判断是否为Promise对象以进行异步等待,否则直接执行下一个yield