循环与回调函数

本文探讨了在Node.js中使用fs模块进行异步操作时,尤其是在循环中嵌套回调函数所遇到的挑战。通过分析示例代码,解释了因异步执行顺序导致的错误结果,并提出了将异步转化为同步以解决问题的方法。

nodejs中的fs模块所提供的接口都是异步操作,当循环中嵌套回调函数时回遇到很多问题
如我想实现一个目的:
这里写图片描述
上图是album文件夹下的子目录,我现在想把其中所有的文件夹存入一个数组中去,代码如下:

var http = require('http');
var fs = require('fs');
var server = http.createServer(function (req,res) {
    //不处理小图标
    if(req.url == '/favicon.ico'){
        return;
    }
    //stat检测状态
    // fs.stat('./album/aaa',function (err,data) {
    //     //检测这个路径是不是一个文件夹
    //     console.log(data.isDirectory());
    // });

    var array  = [];
    fs.readdir('./album',function (err,file) {
        if(err){
            throw err;
        }else{
            //file是一个数组,表示./album这个文件夹中所有的东西
            //包括文件文件夹
            // console.log(file);

            for(var i = 0;i<file.length;i++){
                //这里的thefilename是每个文件在当前文件中的路径
                var thefilename = file[i];
                //又需要再进行一次检测
                fs.stat('./album/'+thefilename,function (err,stats) {
                  if(stats.isDirectory()){
                      array.push(thefilename);
                  }
                })
                //每循环一次将数组的结果输出
             console.log(array);
            }
        }
    })
    res.end();
    console.log(1);
});
server.listen(1000,'127.0.0.1');

但输出结果如下:
这里写图片描述
我们惊讶的发现全是空数组,好吧,发生了什么?仔细思考一下,原来是因为fs模块中提供的方法都是异步操作,所以在执行异步操作读文件状态时
这里写图片描述
由于它是一个异步操作,所以它会立刻转而去执行下面的语句,console.log(array);等到读文件状态操作完成以后才会去触发其对应的异步回调函数,由于读文件状态这个操作相对于控制台输出这个语句耗费的时间要长很多,所以,数组中还没来得及追加任何元素,空数组就这样一次又一次被输出了,所以每一次的输出结果都是空数组。
好,那既然这样,我们就把输出语句放在异步回调函数之内代码如下:

var http = require('http');
var fs = require('fs');
var server = http.createServer(function (req,res) {
    //不处理小图标
    if(req.url == '/favicon.ico'){
        return;
    }
    //stat检测状态
    // fs.stat('./album/aaa',function (err,data) {
    //     //检测这个路径是不是一个文件夹
    //     console.log(data.isDirectory());
    // });

    var array  = [];
    fs.readdir('./album',function (err,file) {
        if(err){
            throw err;
        }else{
            //file是一个数组,表示./album这个文件夹中所有的东西
            //包括文件文件夹
            // console.log(file);

            for(var i = 0;i<file.length;i++){
                //这里的thefilename是每个文件在当前文件中的路径
                var thefilename = file[i];
                //又需要再进行一次检测
                fs.stat('./album/'+thefilename,function (err,stats) {
                  if(stats.isDirectory()){
                      array.push(thefilename);
                  }
                    console.log(array);
                })
            }
        }
    })
    res.end();
});
server.listen(1000,'127.0.0.1');
console.log(1);

下面我们来看一看输出结果:
这里写图片描述
纳尼,发生了什么,输出的文件名居然都是’xiaohu.txt’,而且这货’xiaohu.txt’压根就不是一个文件夹,这什么情况,没关系,冷静下来想一想,欧哦,还是异步有关系呀。。
举例分析,当我们执行读文件状态操作,遍历到aaa文件夹时,这时候主线程不会停留在这里等待,而是继续执行后面的语句,再执行读文件状态操作。这时候,我们循环中的thefile值一直在随着for循环的遍历在改变,这时候,读文件aaa状态操作完成,它通知主线程,啦啦啦,我完成了,执行我的回调函数吧,于是主线程很happy的去执行其对应的回调函数中的操作。就是将thefile追加的数组中去,但是,但是,但是,这时候,thefile这货它已经变成了xiaohu.txt,而不是我们想要的对应的文件夹的名称,就会出现上面的结果,呜呜呜,好伤心,我们该怎么办….
好,那既然这货这么恶心,那么我们就强行将异步转化为同步

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是一个存放了album文件中所有文件的数组
  //定义一个数组用于存放文件夹
  var array = [];
  (function iterator(i){
  //判断数组长度是否越界
  if(i == files.length){
         console.log(array);
         return;
 }
     fs.stat('./album/'+files[i],function(err,stats){
            if(stats.isDirectory()){
                array.push(files[i]);
          }
          //将读取下一个文件状态的操作放在异步回调函数中,这样,只有上一个文件的异步读取操作完成之后才能去读取下一个
          iterator(i+1);
   })
  })(0);
})

})

这里写图片描述
这样我们就可以得到正确的结果啦

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值