Nodejs fs.readdir的问题

Nodejs fs.readdir的问题

从node.js + express4 写一个自己的博客网站教程中写代码,发现获取所有文件夹下的文件,最终结果如何在外面得到呢??return 返回的不是getBlogList的返回值吧?

function getBlogList(blogDir) {
  fs.readdir(blogDir, function (err, files) {
    var blogList = [];
    if (files && files.length) {
        files.forEach(function (filename) {
          //split file name and generate url...
          //...
          //create a blogItem { title: blogTitle, url: blogUrl }
          blogList.push(blogItem);
        });
    }
    return blogList;
  });
}

刚接触node,疑惑很久,请各位赐教~谢谢


10 回复

从node.js + express4 写一个自己的博客网站教程中写代码,发现获取所有文件夹下的文件,最终结果如何在外面得到呢??return 返回的不是getBlogList的返回值吧?

function getBlogList(blogDir) {
  fs.readdir(blogDir, function (err, files) {
    var blogList = [];
    if (files && files.length) {
        files.forEach(function (filename) {
          //split file name and generate url...
          //...
          //create a blogItem { title: blogTitle, url: blogUrl }
          blogList.push(blogItem);
        });
    }
    return blogList;
  });
}

刚接触node,疑惑很久,请各位赐教~谢谢


由于fs.readdir为异步操作,你可以使用回调函数来做:

function getBlogList(blogDir, callback) {
  fs.readdir(blogDir, function (err, files) {
    var blogList = [];
    if (files && files.length) {
        files.forEach(function (filename) {
          //split file name and generate url...
          //...
          //create a blogItem { title: blogTitle, url: blogUrl }
          blogList.push(blogItem);
        });
    }
    callback(blogList);
  });
}

getBlogList的使用是这样:

getBlogList('<BLOG_DIR>', function(list) {
// You can get blog list here.
});

当然可以。你遇到的问题主要是因为 fs.readdir 是一个异步函数,而你在尝试以同步的方式处理它的返回值。在 Node.js 中,异步函数不会直接返回值,而是通过回调函数来传递结果。因此,你需要使用回调函数或者 Promises 来处理这种异步操作。

下面是一个修改后的示例,展示了如何正确地处理 fs.readdir 的结果,并将其传递给外部函数:

使用回调函数

const fs = require('fs');

function getBlogList(blogDir, callback) {
  fs.readdir(blogDir, function (err, files) {
    if (err) {
      return callback(err); // 如果有错误,将错误传递给回调函数
    }

    var blogList = [];
    if (files && files.length) {
      files.forEach(function (filename) {
        // 假设我们根据文件名生成标题和 URL
        const blogTitle = filename.replace('.md', '');
        const blogUrl = `/blog/${blogTitle}`;
        
        // 创建一个包含标题和 URL 的对象
        const blogItem = { title: blogTitle, url: blogUrl };
        blogList.push(blogItem);
      });
    }

    callback(null, blogList); // 将结果传递给回调函数
  });
}

// 调用 getBlogList 并传递回调函数
getBlogList('./blogs', function (err, blogList) {
  if (err) {
    console.error('Error:', err);
    return;
  }
  
  console.log('Blog List:', blogList);
});

使用 Promises

如果你更喜欢使用 Promises,可以使用 fs.promises.readdir 方法,该方法返回一个 Promise,可以在 .then 方法中处理结果。

const fs = require('fs').promises;

async function getBlogList(blogDir) {
  try {
    const files = await fs.readdir(blogDir);

    var blogList = [];
    if (files && files.length) {
      files.forEach(function (filename) {
        // 假设我们根据文件名生成标题和 URL
        const blogTitle = filename.replace('.md', '');
        const blogUrl = `/blog/${blogTitle}`;
        
        // 创建一个包含标题和 URL 的对象
        const blogItem = { title: blogTitle, url: blogUrl };
        blogList.push(blogItem);
      });
    }

    return blogList; // 返回 Promise 的结果
  } catch (err) {
    throw err; // 抛出错误以便外部处理
  }
}

// 调用 getBlogList 并使用 .then 和 .catch 处理结果
getBlogList('./blogs')
  .then(blogList => {
    console.log('Blog List:', blogList);
  })
  .catch(err => {
    console.error('Error:', err);
  });

在这两个示例中,我们都确保了异步操作的结果能够正确地传递到外部函数。希望这能帮助你理解如何处理异步操作并获取正确的结果。

function getBlogList(blogDir, callback) {
  fs.readdir(blogDir, function (err, files) {
  	if(err) return callback(err);
    var blogList = [];
    if (files && files.length) {
        files.forEach(function (filename) {
          //split file name and generate url...
          //...
          //create a blogItem { title: blogTitle, url: blogUrl }
          blogList.push(blogItem);
        });
    }
    return callback(null, blogList);
  });
}
getBlogList('dir', function(err, list){
	handle(list);
});

现在我终于知道为什么async不够用,需要promise,我也知道为什么promise也不够用了,要generator,我也知道generator为什么不够用了,要fibjs,都是异步惹得祸啊。

楼主如果需要遍历目录内的目录的话,恐怕还要加点代码。给个参考dir 看看着那一层层的回调,有的人深恶痛绝,有的却是很喜欢的,我就是喜欢的那种人。

顺便求高人用promise也实现一个,让我顺便学习一下promise的用法,回调其实倒不可怕,可怕的是那些一层又一层的错误处理,promise只懂皮毛,还望大神来答疑。

[@coordcn](/user/coordcn) 嘿嘿 学习啦~~谢谢

var Promise = require("bluebird"),
	readDir = Promise.promisify(require("fs").readdir);
	
readDir(blogDir)
.then(function(files){
	var blogList = [];
    if (files && files.length) {
        files.forEach(function (filename) {
          //split file name and generate url...
          //...
          //create a blogItem { title: blogTitle, url: blogUrl }
          blogList.push(blogItem);
        });
    }
	return blogList;
})
.then(handle)
.catch(SyntaxError,function(e){
	//File error
})
.catch(function(e){
	//any other error
})

太棒了,遇到了同样的问题,谢谢:)

我去,踩到盗洞了。还以为 2 楼在开嘲讽。6楼支持你直接 fs.readdirSync

在Node.js中,fs.readdir 是一个异步函数,这意味着它不会立即返回结果。因此,直接使用 return 语句无法将结果返回到调用者。为了处理这种情况,你需要使用回调函数来传递结果。

以下是修改后的示例代码:

const fs = require('fs');

function getBlogList(blogDir, callback) {
  fs.readdir(blogDir, function (err, files) {
    if (err) {
      return callback(err);
    }

    var blogList = [];
    if (files && files.length) {
      files.forEach(function (filename) {
        // 假设这里生成了 blogItem 对象
        const blogItem = {
          title: filename,
          url: `/blog/${filename}`
        };
        blogList.push(blogItem);
      });
    }

    callback(null, blogList);
  });
}

// 调用 getBlogList 函数,并提供一个回调函数来处理结果
getBlogList('./blogs', function (err, blogList) {
  if (err) {
    console.error('Error:', err);
    return;
  }
  
  console.log('Blog List:', blogList);
});

解释

  1. 异步操作fs.readdir 是一个异步操作,所以不能简单地用 return 返回结果。
  2. 回调函数:通过传递一个回调函数给 getBlogList,可以在读取文件后执行该回调函数,并传入结果。
  3. 错误处理:如果读取文件时发生错误,会通过回调函数的第一个参数(通常是错误对象)返回错误信息。
  4. 数据处理:在 callback 中传递处理后的 blogList 数据。

这样可以确保在 fs.readdir 完成后正确地处理结果。

回到顶部