【问题标题】:Function behaving asynchronously even after a callback function in Node.js即使在 Node.js 中的回调函数之后,函数也会异步执行
【发布时间】:2018-06-24 15:14:51
【问题描述】:

我正在尝试使用 Node.js 的“fs”模块制作文件资源管理器。

我编写了以下函数,它接受一个路径并将该路径(文件/文件夹)的内容存储在一个数组中,然后使用回调将其发送回。

listDir: function (path, myCallback) {
    var resultObj = [];

    fs.readdir(path, function (err, data) {
        console.log('In listDir');
        if (err) {
            return myCallback(err, null);
        } else {

            data.forEach(function (value) {

                fs.lstat(path + '/' + value, function (err, stats) {

                    if (err) {
                        console.log(err);
                    } else {
                        //console.log('Size-' + stats.isFile()+'\n');
                        if(stats.isFile()){
                            //console.log('is file----\n');
                            /*resultObj.push({
                                type: 'file',
                                name: value,
                                size: stats['size']
                            });*/
                            resultObj.push(value);
                            console.log(resultObj+'\n');

                        } else if(stats.isDirectory()){
                            //console.log('is folder----\n');
                            /*resultObj.push({
                                type: 'folder',
                                name: value,
                                size: stats['size']
                            });*/
                            resultObj.push(value);
                            console.log(resultObj+'\n');
                        }
                    }
                });

            });
            console.log('Resultant obj-' + resultObj);
            return myCallback(null, resultObj);
        }
    });

}

对于存储在“数据”中的每个文件/文件夹,我正在尝试检查它是文件还是文件夹,并且取决于我想将对象推送到我的“resultObj”数组中。 但是,return 语句甚至在 forEach 完成之前就被执行,因此我每次都得到一个空的 resultObj。

为什么会这样?为什么即使我提供了回调函数,它也会异步运行?

当我使用路径参数调用 /test 路由时,输出是这样的--

在列表目录中
结果 obj-
GET /test?path=F:\dummyFolder 304 15.210 毫秒 - -
文件1
文件 1,文件 2
文件 1、文件 2、文件夹 3

请帮帮我,我真的被这个必须在今晚完成的任务所困。并且在任务不使用'fs'模块的任何同步函数中也特别提到了这一点。 那么我如何才能牢记该条款呢?

PS:不要介意cmets,我用它们来调试。

【问题讨论】:

    标签: javascript node.js callback node-modules fs


    【解决方案1】:

    问题是您没有等待fs.lstat() 函数为每个文件完成。您正在排队所有fs.lstat() 呼叫,但没有等待所有呼叫完成。当它仍然是[] 时,您将返回resultObj

    您可以通过在 data.forEach() 的回调中添加检查来解决此问题,以查看有多少项目已调用 fs.lstat() 的回调。

    listDir: (path, myCallback) => {
        let resultObj = [];
    
        fs.readdir(path, (err, data) => {
          console.log('In listDir');
          if (err) {
              return myCallback(err);
          }
    
          let itemsCompleted = 0        
          data.forEach(value => {
            fs.lstat(path + '/' + value, (err, stats) => {
              itemsCompleted++
              if (err) {
                console.log(err);
              } else {
                if(stats.isFile() || stats.isDirectory()){
                  resultObj.push(value);
                  console.log(resultObj+'\n');
                }
              }
    
              if(itemsCompleted >= data.length) {
                return myCallback(null, resultObj)
              }
            });            
        });
    }
    

    但是,上面的方法仍然比带有async/await 的 Promises 更复杂。带有async/await 的 Promise 是目前在 Node.js 中处理异步控制流的首选方式。利用util.promisify() 承诺fs.readdir()fs.lstat() 使我们能够扁平化控制流并显着提高listDir() 的可读性。此外,通过使用map() 而不是forEach(),我们可以使用Promise.all() 为每个条目包装从lstatAsync() 返回的Promise。

    const {promisify} = require('util')
    const fs = require('fs')
    const {join} = require('path')
    const readdirAsync = promisify(fs.readdir)
    const lstatAsync = promisify(fs.lstat)
    
    module.exports = {
      listDir: async path => {
        let resultObj = []; 
    
        let entries = await readdirAsync(path)
        console.log('In listDir');
    
        await Promise.all(entries.map(async value => {
          try {
            let stats = await lstatAsync(join(path, value))
    
            if(stats.isFile() || stats.isDirectory()){
              resultObj.push(value);
              console.log(resultObj+'\n');
            }
          } catch (err) {
            console.log(err)
          }
        }))
    
        return resultObj
      }
    }
    

    【讨论】:

    • 非常感谢!完美运行。
    猜你喜欢
    • 2013-02-02
    • 2020-10-26
    • 1970-01-01
    • 2019-01-20
    • 2015-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多