规定Node.js

我最近已经开始使用Node.js,并且遇到了一个需要关于完成任务的规定性node.js方法的小指导。 在这个特殊的情况下,我需要创build一堆目录,当所有的目录都创build完毕后,我需要执行一些最终的操作。 创build目录的顺序并不重要,我只需要在最后一个操作之后执行最后的操作。

最简单的方法是回到旧的同步习惯。 也就是说,只需为每个目录调用fs.mkdirSync并在最后执行操作即可。 例如:

 fs.mkdirSync('a', 0755); fs.mkdirSync('a/b', 0755); fs.mkdirSync('a/b/c', 0755); performFinalOperation(); 

虽然这会起作用,但它并不像Node.js这样做的方式。 很明显,程序会在等待操作系统创build目录并返回时阻塞。 在远程安装文件系统的重负载系统上,每个mkdirSync调用可能需要很长时间。 很显然,这不是最好的方法。

Node.js的一个主要卖点是它是asynchronous的。 所以fs.mkdir的调用可以通过callback来链接:

 fs.mkdir('a', 0755, function(e) { if (!e) { fs.mkdir('a/b', 0755, function(e) { if (!e) { fs.mkdir('a/b/c', 0755, function(e) { if (!e) { performFinalOperation(); } }); } }); } }); 

再次,我确信这种方法是有效的,但是它导致了非常深的嵌套和代码重复。 它具有在创build目录时不阻塞的好处,但成本是多less?

另一种方法是非常喜欢避免代码重复和嵌套:

 (function (directories) { if (directories.length === 0) { performFinalOperation(); } else { var tail = arguments.callee; fs.mkdir(directories.shift(), 0755, function(e) { tail(directories); }); } })(['a', 'a/b', 'a/b/c']); 

这种方法使用各种疯狂的东西:匿名自我调用函数和魔法arguments.callee。 但最糟糕的是,乍看之下代码的作用并不明显。

所以,虽然具体的问题是关于创build目录,但我更关心的是,当这种情况出现时,经验丰富的node.js老手会采取的方法。 我特别对图书馆所处的地方感兴趣。

哦,嘿布赖恩:)

我特别对图书馆所处的地方不感兴趣。

经验丰富的Node老手已经写了至less一个自己的控制stream库。 我们刚刚复制了Twisted的Deferred类,因为他们已经做了asynchronous编程的努力和研究。 这反过来标准的callback作为参数模式,我喜欢得到的代码,但是如果你想嵌套一堆callback,你仍然可以用Deferred来做到这一点,并最终得到一个混乱。

由于不使用图书馆的限制,人们通常会完全按照你所写的来做。 真的没有其他的select。 没有像生成器这样的语言变化,我们能做的最好的就是使用库。 如果你不想使用现有的一个,你最终会自己动手,或者只是写很多样板。

您的第二个解决scheme可以大大简化,并包括这样的错误:

 var mkdirs = function(dirs, mode, cb){ (function next(e) { (!e && dirs.length) ? fs.mkdir(dirs.shift(), mode, next) : cb(e); })(null); }; 

npm安装mkdirp

 var mkdirp = require('mkdirp').mkdirp; mkdirp('/tmp/foo/bar/baz', 0755, function (err) { if (err) console.error(err) else console.log('pow!') }); 

我相信这样做的方式是与一个柜台。 从目录的数量开始,然后在每个操作完成时递减。 此时也testing为零并执行最终操作。

请参阅http://howtonode.org/control-flow-part-iii

嗯,这是猜测,我几乎不知道任何Javascript,但这样的最终结果怎么样?

 Asynchronously .Do(function(callback) { fs.mkdir('a', 0755, callback); }) .Then(function(result, callback) { if(!result) fs.mkdir('a/b', 0755, callback); }) .Then(function(result, callback) { if(!result) fs.mkdir('a/b/c', 0755, callback); }) .Then(function(result, callback) { if(!result) performFinalOperation(); }); 

我会build议寻找步骤 。 它使得从同步到asynchronous的转换变得更容易。

  • 经验丰富的老兵写了图书馆来简化这一点。 你不想听到这个,所以我不会去详细的细节,但我真的很喜欢async.js 。
  • 另外这个post(video)来自雅虎! 避免写意大利面代码非常有趣

这个方法怎么样? 我认为这是非常明确的,它处理错误,并没有使用arguments.callee这是比我通常更舒适的魔术。

 var fs = require('fs'); function mkdirs(dirs, cb, err) { if (err) { return cb(err); } if (dirs.length === 0) { return cb(); } var dir = dirs.shift(); fs.mkdir(dir, mkdirs.bind(this, dirs, cb)); } // Test it. mkdirs(['a', 'a/b', 'a/b/c'], function (e) { if (e) { return console.log("An error:", e); } console.log("No error."); });