Generator 运行时上下文
一个最重要的概念,是去弄清楚,当你编写一个generator的时候,其中的方法是如何运行的和在哪个上下文中
被当作action的prototype方法
每个被添加到generator原型链上的方法都会被当成一个任务.每个任务都跑在一个队列中,这个队列由yeoman的运行环境来决定
换句话说,通过Object.getPrototypeOf(Generator) 返回的每个函数都会被自动运行
帮助函数和私有函数
你现在知道prototype上的方法都会被当作是一个任务,你可能想知道怎么去定义一些帮助函数和私有函数(不会被当作任务自动运行的函数).这里有三种方式来完成这点.
- 通过“_”来作为方法前缀,比如”_private_say”
- 使用实例方法
generators.Base.extend({
constructor: function () {
this.helperMethod = function () {
console.log('won\'t be called automatically');
};
}
});
扑满大师:了解js的人应该知道,直接上述的方式写,其实是不绑定在prototype上的
- 扩展父类generator
var MyBase = generators.Base.extend({
helper: function () {
console.log('methods on the parent generator won\'t be called automatically');
}
});
module.exports = MyBase.extend({
exec: function () {
this.helper();
}
});
扑满大师:很取巧的方式,因为Object.getPrototypeOf(Generator) 是不会找prototype的prototype的
运行循环圈
运行单个的generator,那么运行队列是很清楚的.但是一旦你要把多个generator组合在一起使用,那么这个还不够
这个是为什么yeoman使用运行循环圈 的原因
运行循环圈是一个优先队列系统.我们使用分组队列模块来处理它
优先权在你的代码中被定义,它们要被命名为特殊的prototype名字.当方法名被定义成”priorityName”这样的格式的时候,运行循环圈会把这个方法压入特殊的队列.如果不是,那么会被压入默认的组中
在代码中,它应该是这样:
generators.Base.extend({
priorityName: function () {}
});
你也可以把多个方法放在一个对象中赋值给priorityName,请注意他们的运行顺序
generators.Base.extend({
priorityName: {
method: function () {},
method2: function () {}
}
});
一些可能的优先权的值(以运行顺序排列):
- initializing - 你的初始方法 (检查当前工程状态,读取配置文件等等)
- prompting - 当你提醒用户来确定一些选项的时候(你需要使用this.prompt())
- configuring - 保存配置和配置工程(创建.editorconfig文件和其他的一些元数据文件)
- default - 如果方法名不配对priority,那么会被压入这个group
- writing - 创建generator的特定文件(比如routes, controllers等等)
- conflicts - 冲突的时候
- install - 使用npm bower等工具进行安装的时候
- end - 最后调用,清理
跟随这些priority的知道,你的generator会跟其他的generator很好的共同工作
异步任务
有很多方法可以来暂停”运行循环圈”,直到异步任务已经被完成
最简单的方式就是返回一个promise.一旦promise完成了,那么循环圈会继续;如果promise失败了,那就会抛出一个错误,并且停止.
如果你依赖的异步api不是promise方式的,那么你可以用this.async()方式,调用它会返回一个function,在任务中调用这个function,yeoman就知道你的任务完成了
asyncTask: function () {
var done = this.async();
getUserEmail(function (err, name) {
done(err);
});
}
如果done函数被调用的时候带上了error参数,那么”运行循环圈”会被停止,并且抛出一个错误