规定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为零并执行最终操作。
嗯,这是猜测,我几乎不知道任何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."); });