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");
原文地址:https://www.cnblogs.com/zhangmingzhao/p/7741083.html