编辑: 笨蛋爱傻瓜悦 | 2019-07-09 |
6 {value: xxx, done: false} 当 generator 运行到 yield 关键字时,generator 就会进入暂态.如果在调用 next 方法时传递了参数 next(param) ,则能将 param 传回 generator 流程, 这在调用异步过程时非常有用,如上面代码片中的 returnTwoAsync 、 returnThreeAsync 所示. 利用 generator 组织异步流程 假设一个业务流程中穿插了多个异步过程,除了进行传统的回调解决策略,也可借 助于 generator 进行解决,但需要做如下改造: 通过 generator 函数来组织业务流程,可以通过 yield 来等待异步流程执行 完毕,通过 try-catch 进行错误处理: function* gen() { try { let data1 = yield callback1();
catch (e) { console.error(e);
} let data2 = yield callback2();
} } // 调用generator函数,获得操纵generator执行过程的迭代器对象 const it = gen();
// 首次调用`next`方法,驱动generator开始执行 it.next() 改造异步方法: 遇到错误通过迭代器对象的 throw(error) 方法抛出错误,使得外部能够通 过 try-catch 进行错误处理. 如果没有发生错误,则可以继续业务流程,并利用传递参数的 next() 方法 告知 generator 运行结果,并继续 generator 函数的执行. 利用 generator 组织异步流程
7 function callback(err, data) { if(err) { 抛出错误 it.throw(err);
} else { it.next(data);
} } 综上,利用 generator,上一节的文件大小统计代码就可以这样撰写: 利用 generator 组织异步流程
8 const fs = require('
fs'
);
// 改造size方法 function size(filename) { fs.stat(filename, function(err, stat) { if(err) it.throw(err);
else it.next(stat.size);
});
} function *main() { const sizeInfo = { file1'
: 0, file2'
: 0, file3'
:
0 };
try { sizeInfo['
file1'
] = yield size('
file1.md'
);
sizeInfo['
file2'
] = yield size('
file2.md'
);
sizeInfo['
file3'
] = yield size('
file3.md'
);
} catch(e) { console.error(e);
} console.log(sizeInfo);
} const it = main();
// 驱动iterator运行 it.next();
可以看到,借助于 generator,我们可以用传统的阻塞式的、同步式的代码来撰写 业务逻辑,也可以通过 try-catch 进行错误处理,但是,需要进行一定程度侵 入式的改造,假设原有
100 个异步函数,我们就需要改造这
100 个函数,并且还 担心这样的改造影响到原有的业务流程,因此,我们还需要进一步的处理,首先, 我们会考虑创建一个运行器,来驱动我们的 generator 运行. 利用 generator 组织异步流程
9 执行器 上一节中,我们利用 generator,实现了以同步式代码的形式来组织异步流程,但是,如果我们有多个 generator 函数,则需要手动驱动每个 generator 的运行,而 且这些代码大体是重复的: function *gen1(){} function *gen2(){} function *gen3(){} let it1 = gen1();
let it2 = gen2();
let it3 = gen3();
it1.next();
it2.next();
it3.next();
因此,我们考虑设计一个执行器(runner),来驱动 generator 的运行: 运行器
10 /** * 运行器 * @param {Generator} generatorFunc */ function runGenerator(generatorFunc) { // 获得generator迭代器 let it = generatorFunc();
next();
/** * 自定义一个next函数 */ function next(err, res) { if (err) { it.throw(err);