Kir*_*met 8 javascript asynchronous generator node.js ecmascript-6
我一直对Node JS感到非常兴奋.我最终决定关注并编写一个测试项目,以了解最新的Harmony构建Node中的生成器.
这是我非常简单的测试项目:
https://github.com/kirkouimet/project-node
要运行我的测试项目,您可以轻松地从Github中提取文件,然后运行它:
node --harmony App.js
Run Code Online (Sandbox Code Playgroud)
这是我的问题 - 我似乎无法让Node的异步fs.readdir方法与生成器内联运行.其他项目,如Galaxy和暂停似乎能够做到这一点.
这是我需要修复的代码块.我希望能够实例化FileSystem类型的对象并在其上调用.list()方法:
FileSystem = Class.extend({
construct: function() {
this.currentDirectory = null;
},
list: function*(path) {
var list = yield NodeFileSystem.readdir(path);
return list;
}
});
Run Code Online (Sandbox Code Playgroud)
我是否需要提前做一些事情才能将Node的fs.readdir转换为生成器?
一个重要的注意事项,我正在解析创建它们时的所有类函数.这使我能够处理生成器函数与普通函数不同:
我对这个项目感到非常难过.会喜欢任何帮助!
这是我想要完成的:
我试图实现你的示例函数,我遇到了一些麻烦.
list: function*(path) {
var list = null;
var whatDoesCoReturn = co(function*() {
list = yield readdir(path);
console.log(list); // This shows an array of files (good!)
return list; // Just my guess that co should get this back, it doesn't
})();
console.log(whatDoesCoReturn); // This returns undefined (sad times)
// I need to use `list` right here
return list; // This returns as null
}
Run Code Online (Sandbox Code Playgroud)
log*_*yth 17
首先,重要的是要有一个好的模型在你的头脑中确切地说是发电机.生成器函数是一个返回生成器对象的函数,该生成器对象将yield在您调用生成器函数时逐步执行生成器函数中的语句.next().
鉴于该描述,您应该注意到未提及异步行为.对发电机本身的任何动作都是同步的.您可以yield立即运行到第一个然后执行a setTimeout然后调用.next()以转到下一个yield,但它setTimeout会导致异步行为,而不是生成器本身.
所以,让我们根据这一点投下这个fs.readdir.fs.readdir是一个异步函数,在它自己的生成器中使用它将没有任何效果.我们来看看你的例子:
function * read(path){
return yield fs.readdir(path);
}
var gen = read(path);
// gen is now a generator object.
var first = gen.next();
// This is equivalent to first = fs.readdir(path);
// Which means first === undefined since fs.readdir returns nothing.
var final = gen.next();
// This is equivalent to final = undefined;
// Because you are returning the result of 'yield', and that is the value passed
// into .next(), and you are not passing anything to it.
Run Code Online (Sandbox Code Playgroud)
希望它能让你更清楚的是你仍在readdir同步调用,并且你没有传递任何回调,所以它可能会抛出错误或其他东西.
通常,这是通过让生成器产生一个特殊对象来实现的,该对象表示在readdir实际计算值之前的结果.
对于(不切实际的)示例,yield函数是一种产生代表值的简单方法.
function * read(path){
return yield function(callback){
fs.readdir(path, callback);
};
}
var gen = read(path);
// gen is now a generator object.
var first = gen.next();
// This is equivalent to first = function(callback){ ... };
// Trigger the callback to calculate the value here.
first(function(err, dir){
var dirData = gen.next(dir);
// This will just return 'dir' since we are directly returning the yielded value.
// Do whatever.
});
Run Code Online (Sandbox Code Playgroud)
实际上,您希望这种类型的逻辑继续调用生成器,直到完成所有yield调用,而不是对每个调用进行硬编码.尽管如此,要注意的主要事情是,现在生成器本身看起来是同步的,并且read函数外部的所有东西都是超级通用的.
您需要某种处理此屈服值过程的生成器包装函数,并且您的示例suspend正是如此.另一个例子是co.
"返回表示值的东西"方法的标准方法是返回a promise或a,thunk因为返回一个像我这样的函数有点难看.
使用thunk和co库,您可以在没有示例函数的情况下执行上述操作:
var thunkify = require('thunkify');
var co = require('co');
var fs = require('fs');
var readdir = thunkify(fs.readdir);
co(function * (){
// `readdir` will call the node function, and return a thunk representing the
// directory, which is then `yield`ed to `co`, which will wait for the data
// to be ready, and then it will start the generator again, passing the value
// as the result of the `yield`.
var dirData = yield readdir(path, callback);
// Do whatever.
})(function(err, result){
// This callback is called once the synchronous-looking generator has returned.
// or thrown an exception.
});
Run Code Online (Sandbox Code Playgroud)
您的更新仍然有一些混乱.如果您希望您的list函数成为生成器,那么您将需要在您调用它的任何地方co 之外使用list.内部的co所有内容都co应该基于生成器,外部的所有内容都应该基于回调.co不会list自动异步.co用于将基于生成器的异步流控制转换为基于回调的流控制.
例如
list: function(path, callback){
co(function * (){
var list = yield readdir(path);
// Use `list` right here.
return list;
})(function(err, result){
// err here would be set if your 'readdir' call had an error
// result is the return value from 'co', so it would be 'list'.
callback(err, result);
})
}
Run Code Online (Sandbox Code Playgroud)
@loganfsmyth已经为您的问题提供了很好的答案.我的答案的目的是帮助您了解JavaScript生成器的实际工作方式,因为这是正确使用它们非常重要的一步.
生成器实现了一个状态机,这个概念本身并不新鲜.最新消息是,发电机允许使用熟悉的JavaScript语言构造(如for,if,try/catch),以实现一个状态机不放弃的线性码流.
生成器的最初目标是生成一系列数据,这与异步无关.例:
// with generator
function* sequence()
{
var i = 0;
while (i < 10)
yield ++i * 2;
}
for (var j of sequence())
console.log(j);
// without generator
function bulkySequence()
{
var i = 0;
var nextStep = function() {
if ( i >= 10 )
return { value: undefined, done: true };
return { value: ++i * 2, done: false };
}
return { next: nextStep };
}
for (var j of bulkySequence())
console.log(j);
Run Code Online (Sandbox Code Playgroud)
第二部分(bulkySequence)展示了如何以传统方式实现相同的状态机,没有生成器.在这种情况下,我们不再能够使用while循环来生成值,并且继续通过nextStep回调发生.此代码笨重且难以理解.
我们来介绍一下异步.在这种情况下,状态机下一步的继续将不是由for of循环驱动,而是由某些外部事件驱动.我将使用计时器间隔作为事件的来源,但它也可能是Node.js操作完成回调或promise解析回调.
这样做是为了显示它是如何工作的,而无需使用任何外部库(如Q,Bluebird,Co等).没有什么能阻止发电机自动驾驶到下一步,这就是下面的代码所做的.一旦异步逻辑的所有步骤都完成(10个计时器滴答),doneCallback将被调用.注意,我不会yield在这里返回任何有意义的数据.我只是用它来暂停和恢复执行:
function workAsync(doneCallback)
{
var worker = (function* () {
// the timer callback drivers to the next step
var interval = setInterval(function() {
worker.next(); }, 500);
try {
var tick = 0;
while (tick < 10 ) {
// resume upon next tick
yield null;
console.log("tick: " + tick++);
}
doneCallback(null, null);
}
catch (ex) {
doneCallback(ex, null);
}
finally {
clearInterval(interval);
}
})();
// initial step
worker.next();
}
workAsync(function(err, result) {
console.log("Done, any errror: " + err); });
Run Code Online (Sandbox Code Playgroud)
最后,让我们创建一系列事件:
function workAsync(doneCallback)
{
var worker = (function* () {
// the timer callback drivers to the next step
setTimeout(function() {
worker.next(); }, 1000);
yield null;
console.log("timer1 fired.");
setTimeout(function() {
worker.next(); }, 2000);
yield null;
console.log("timer2 fired.");
setTimeout(function() {
worker.next(); }, 3000);
yield null;
console.log("timer3 fired.");
doneCallback(null, null);
})();
// initial step
worker.next();
}
workAsync(function(err, result) {
console.log("Done, any errror: " + err); });
Run Code Online (Sandbox Code Playgroud)
一旦理解了这个概念,就可以继续使用promises作为生成器的包装器,从而将它带到下一个强大的层次.
| 归档时间: |
|
| 查看次数: |
3427 次 |
| 最近记录: |