NodeJS和asynchronous地狱

我刚刚来到这个可怕的情况,我有一个string的数组,每个代表一个可能存在的文件(例如var files = ['file1', 'file2', 'file3']我需要遍历这些文件名并尝试看看它是否存在于当前目录中,如果存在,停止循环,并忘记其余的剩余文件。所以基本上我想find这些文件的第一个现有的文件,并退回到一个硬编码的消息,如果没有发现。

这是我现在有:

 var found = false; files.forEach(function(file) { if (found) return false; fs.readFileSync(path + file, function(err, data) { if (err) return; found = true; continueWithStuff(); }); }); if (found === false) { // Handle this scenario. } 

这不好。 它阻塞(readFileSync),因此它很慢。

我不能只为fs.readFile提供callback方法,这不是那么简单,因为我需要find第一个find的项目…而且callbackfs.readFile可以以任意顺序调用。 我想一种方法是有一个callback,增加一个计数器,并保持一个find/未find的信息列表,当它到达files.length计数,然后它检查通过find/未find的信息,并决定下一步该怎么做。

这是痛苦的。 我确实看到了IO中的性能优势,但这是不可接受的。 我有什么select?

不要在正常的服务器环境中使用同步的东西 – 事情是单线程的,这将完全locking,而它等待这个io绑定循环的结果。 CLI实用程序=可能很好,服务器=只有在启动时才好。

用于asynchronousstream量控制的通用库是https://github.com/caolan/async

 async.filter(['file1','file2','file3'], path.exists, function(results){ // results now equals an array of the existing files }); 

如果你想说,避免额外的调用path.exists,那么你可以很容易地写一个函数“第一”,做了操作,直到一些testing成功。 类似于https://github.com/caolan/async#until – 但你对输出感兴趣。

asynchronous库绝对是你在找什么。 它以非常好的asynchronous方式提供了几乎所有的迭代types。 尽pipe如此,您不必编写自己的“第一个”函数。 asynchronous已经提供了一个“一些”function,正是这一点。

https://github.com/caolan/async#some

 async.some(files, path.exists, function(result) { if (result) { continueWithStuff(); } else { // Handle this scenario } }); 

如果您或将来某人阅读此文件时不想使用Async,您也可以自行制作“some”的基本版本。

 function some(arr, func, cb) { var count = arr.length-1; (function loop() { if (count == -1) { return cb(false); } func(arr[count--], function(result) { if (result) cb(true); else loop(); }); })(); } some(files, path.exists, function(found) { if (found) { continueWithStuff(); } else { // Handle this scenario } }); 

您可以使用recursion函数在没有第三方库的情况下执行此操作。 传递它的文件名和一个指针的数组,最初设置为零。 函数应该检查数组中是否存在指定的文件名,并且在callback函数中应该执行其他的东西(如果文件存在)或者增加指针并且调用它自己(如果文件不是不存在)。

使用async.waterfall控制node.js中的asynchronous调用,例如:通过在async中包含async-library并使用瀑布调用:

  var async = require('async'); async.waterfall( [function(callback) { callback(null, taskFirst(rootRequest,rootRequestFrom,rootRequestTo, callback, res)); }, function(arg1, callback) { if(arg1!==undefined ) { callback(null, taskSecond(arg1,rootRequest,rootRequestFrom,rootRequestTo,callback, res)); } } ]) 

(编辑:删除同步build议,因为这不是一个好主意,我们不希望任何人复制/粘贴,并在生产代码中使用它,我们?)

如果你坚持使用asynchronous的东西,我认为比你所描述的更简单的方式来实现这一点是做以下几点:

 var path = require('path'), fileCounter = 0; function existCB(fileExists) { if (fileExists) { global.fileExists = fileCounter; continueWithStuff(); return; } fileCounter++; if (fileCounter >= files.length) { // none of the files exist, handle stuff return; } path.exists(files[fileCounter], existCB); } path.exists(files[0], existCB);