<span style="font-family: Arial, Helvetica, sans-serif;"></span><pre name="code" class="javascript">var path = require("path");<pre name="code" class="javascript">var fs = require("fs");
function travelDir( dir, callback ) {
fs.readdirSync( dir ).forEach( function( file) {
var pathname = path.join( dir, file );
if( fs.statSync( pathname ).isDirectory() ) {
travelDir( pathname, callback );
}else {
callback( pathname );
}
} );
}
function travelDirAsync( dir, callback, finish ) {
fs.readdir( dir, function( error, files ) {
if ( files ) {
( function next( i ) {
if ( i < files.length ){
console.log("i=" + i);
console.log(files);
var pathname = path.join( dir, files[i] );
fs.stat( pathname, function( error, stat ) {
if ( stat ){
if ( stat.isDirectory() ) {
travelDirAsync( pathname, callback, function() {
next( i + 1 );
} );
} else {
callback( pathname, function(){
next( i + 1 );
} );
}
} else {
console.log( error.name + ":" + error.message );
}
} );
} else {
// 注意运行上下文
finish && finish();
}
}( 0 ) );
} else {
console.log( error.name + ":" + error.message );
}
} );
}
function main( argv ) {
//sync
/*
travelDir( argv[0], function( pathname ) {
if( path.extname( pathname ) == ".js" ) {
console.log( pathname );
}
} );
*/
//async
travelDirAsync( argv[0], function( pathname,next ) {
console.log( pathname );
next();
}, function() {
console.log("visiting finished.");
} );
}
main( process.argv.slice(2) );
从昨天开始学node.js。这段代码摘自学习中看到的一篇博客,稍作修改,思想上是一样的。
光是理解travelDirAsyn这个方法里代码就花去了3小时的人生,我始终没有弄明白finish函数的意义。一度看的抓狂。最后向我的一个朋友求助后终于弄明白了。
究其原因还是自己在遍历目录上有种思维定式(来源于其他的编程语言,例如java和c)。一开始我总是在那边想这代码是怎么在进入一层目录后返回到上一层目录的呢?看了无数遍的代码也没想明白。
后来朋友跟我说callback函数中的变量i 和 finish函数中的变量i 并不是同一个 i 的时候就恍然大悟了。
原来因为之前的思维定式,忘记了在js里还有运行上下文这东西。每次函数执行的时候都会创建一个运行上下文,保存其中的变量。
假设有遍历的根目录是test
目录层次为:
-test a.js b.js -folder a.txt b.txt c.js
那么在第一次运行遍历函数travelDirAsyn时,创建了一个运行上下文。其中i的初始值为0,files的值为['a.js','b.js','folder','c.js']。遍历到folder的时候i的值为2。再一次运行travelDirAsyn进入folder目录,又创建了一个新的运行上下文。遍历两次后当前运行上下文的i的值为2,if条件不成立跳到else执行finish函数。此时finish函数的执行环境位于之前的运行上下文(因为finish函数最近一次绑定位于之前的运行上下文),执行next( i + 1 ),之前的运行上下文中的 i 的值为2,所以此时执行的也就是 next(3)。最后输出c.js。
新手请多包涵,个人见解,有错欢迎指出。
大家可以复制代码自己运行试试。
命令行:node xxx.js 目录地址