nodejs 异步递归
文章目录
今天继续之前的下载服务器的开发,第一步调用文件的 API 已经成功了,那么今天的目标是列出应用目录下的所有文件(包括子目录)。
1. 最初代码实现
代码的实现主要是用到了异步回调+递归:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
var https = require('https'), config = require('./config'), list = []; function getList(path) { https.get(config.file_url + 'list&access_token=' + config.access_token + '&path=' + path, function(res) { var content = ''; res.setEncoding('utf8'); res.on('data', function(data) { content += data; }); res.on('end', function() { var result = JSON.parse(content); result.list.forEach(function(item) { if (item.isdir === 1) { // 判断是否为目录 getList(item.path, callback); } else { console.log(item.path); list.push(item.path); // handle(list); // 完成处理 list } }); }); }); } getList(config.app_path); |
到这里,貌似已经可以获取所有的文件的。 但是发现了一个问题,那就是什么时候才完成所有的调用,然后对 list 进行下一步的处理呢? 因为 https.get() 是一个异步的方法,我们无法知道什么时候完成。
2. async.each 和 async.eachSeries 的实现
相信聪明的人已经知道怎么解决上面的问题了,但是我并不聪明,一时半会被卡在了这里。 记得之前刚刚看过《JavaScript 异步编程》这本书,里面有提到 async 和 step。 其实有用过了 async 了,但是一直是时间去研究源码,既然自己遇到了问题,那不搞懂也不能罢休。
修改了下,实现很简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
function each(arr, iterator, callback) { callback = callback || function () {}; if (!arr.length) { return callback(); } var completed = 0; arr.forEach(function (x) { iterator(x, function (err) { if (err) { callback(err); callback = function () {}; } else { completed += 1; if (completed >= arr.length) { callback(null); } } }); }); }; function eachSeries(arr, iterator, callback) { callback = callback || function () {}; if (!arr.length) { return callback(); } var completed = 0; var iterate = function () { iterator(arr[completed], function (err) { if (err) { callback(err); callback = function () {}; } else { completed += 1; if (completed >= arr.length) { callback(null); } else { iterate(); } } }); }; iterate(); }; |
其实也不难理解,加了 completed 参数统计完成的数量,两个函数都有 callback 作为结束的函数通知。 有所不同的是 eachSeries 的话是在一次异步请求返回之后才进行下一个请求,这样就相当于实现了同步调用。
3. 最终成果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
var https = require('https'), config = require('./config'), list = []; function getList(path, callback) { https.get(config.file_url + 'list&access_token=' + config.access_token + '&path=' + path, function(res) { var content = ''; res.setEncoding('utf8'); res.on('data', function(data) { content += data; }); res.on('end', function() { var result = JSON.parse(content); each(result.list, function(item, callback) { if (item.isdir === 1) { getList(item.path, callback); } else { list.push(item.path); callback(); } }, function(err) { callback(); }); }); }); } getList(config.app_path, function() { list.forEach(function(path) { console.log(config.file_url + 'download&access_token=' + config.access_token + '&path=' + path); }); }); |
文章作者 wenzhixin
上次更新 2013-10-26