Node异步污染局部变量问题
看一个例子:
这么一个文件夹:
现在我们用fs模块判断文件夹,并把文件夹的名字放在一个数组里面。
代码:
var http = require("http"); var fs = require("fs"); http.createServer(function(req, res) { if(req.url == "favicon") { return ; } var ddir = []; //stat检测状态 fs.readdir("./album", function(err, files) { //files是一个文件名的数组,并不是文件的数组,表示./album这个文件夹中的所有集合 //包括文件,文件夹 for(var i = 0; i < files.length; i++) { var thefilename = files[i]; // 又要进行一次检测 fs.stat("./album/" + thefilename, function(err,stats) { //如果他是一个文件夹,那么输出它: if(err) { throw err; } if(stats.isDirectory()) { ddir.push(thefilename); } console.log(ddir); }); // console.log(thefilename); } }) }).listen(3000,"127.0.0.1");
这样按照同步的思想是没错的,但是Node是异步执行的,结果:
呀!结果和我们臆想的有点不一样吧。这就是Node在检测stats是不是文件夹的时候,由于是异步语句,还没有检查完,就已经开始执行下一次了,下一次的时候thefilename变成了bbb,这时候第一个事件的检查文件的异步语句完成了,push进ddir数组,push的thefilename是bbb,第二个事件也只有bbb了,所以最后输出的是良哥bbb。前面三个空是三个异步语句注册的三个事件进入队列,这时候同步执行的下面的console.log(ddir);都还是空数组。
那么问题就来了,怎么解决呢?
闭包解决,递归
var http = require("http"); var fs = require("fs"); var server = http.createServer(function(req, res) { //不处理收藏夹小图标 if(req.url == "favicon.ico") { return ; } //遍历album里面的所有文件,文件夹 fs.readdir("./album/", function(err, files) { //files是一个存放文件(夹)名的数组 //files: ["aaa","bbb","1.txt","1.txt副本"] //存放文件夹的数组wenjianjia var wenjianjia = []; //迭代器就是强行把异步的函数,变成同步的函数 //0做完了,做1,1做完了,再做2,再做3 (function iterator(i) { //遍历结束 if(i == files.length) { console.log(wenjianjia); return ; } fs.stat("./album/" + files[i], function(err, stats) { //检测成功之后做的事情 if(stats.isDirectory()) { //如果是文件夹,那么放入数组。不是,什么也不做 wenjianjia.push(files[i]); } //递归 iterator(i+1); }); })(0); }); res.end(); }) server.listen(3000,"127.0.0.1");
重构一下:
var http = require("http"); var fs = require("fs"); var wenjianjia = []; function iterator(i,files) { //遍历结束 if (i == files.length) { console.log(wenjianjia); return; } fs.stat("./album/" + files[i], function(err, stats) { //检测成功之后做的事情 if (stats.isDirectory()) { //如果是文件夹,那么放入数组。不是,什么也不做。 wenjianjia.push(files[i]); } iterator(i + 1, files); }); } var server = http.createServer(function(req, res) { //不处理收藏夹小图标 if (req.url == "/favicon.ico") { return; } //遍历album里面的所有文件、文件夹 fs.readdir("./album/", function(err, files) { //files : ["0.jpg","1.jpg" ……,"aaa","bbb"]; //files是一个存放文件(夹)名的数组 //存放文件夹的数组 //album读完了,执行回调函数,此时才有files,同步-》异步-》回调 //迭代器就是强行把异步的函数,变成同步的函数 //1做完了,再做2;2做完了,再做3 iterator(0,files); }); res.end(); }); server.listen(3000, "127.0.0.1");