nodejs 同步读取文件

readFile synchronously nodejs

我是nodejs新手,刚开始学习。我需要读取 5 json 个文件并将它们放在一个数组中。我创建了 2 个函数:readDirectory 和 processFile。

    let transactionArray = [];
    router.get('/', (req,res) => {
    
    //joining path of directory 
    const directoryPath = path.join(__dirname, '../data');
    
    readDirectory(directoryPath);
    
    res.send(JSON.stringify(transactionArray))
    
    })

readDirectory 将获取目录并读取文件名。

    function readDirectory(directoryPath){
        //passsing directoryPath and callback function
    fs.readdir(directoryPath, function (err, files) {
        //handling error
        if (err) {
            return console.log('Unable to scan directory: ' + err);
        } 
        //listing all files using map
        let fileSummary = files.map(file => {
            
            //get the filename
            let categoryName = ''
    
            if (file.includes('category1')) {
                 categoryName = 'category1'
            } else if (file.includes('category2')) {
                 categoryName  = 'category2'
            } else {
                categoryName = 'Others'
            }
    
            // read the file
            const filePath = directoryPath +'/'+ file
    
            fs.readFile(filePath, 'utf8', (err, fileContents) => {
                if (err) {
                  console.error(err)
                  return
                }
                try {
                  let data = JSON.parse(fileContents, categoryName)
                  processFile(data, categoryName);
                   
                } catch(err) {
                    console.error(err)
                }
            })   
        }) 
    });    
    }

然后它将使用函数 processFile.

读取文件
function processFile(data, categoryName)
{
    let paymentSource = ''

    if (categoryName == 'category1'){
       paymentSource = categoryName +': '+ categoryName +' '+ data.currency_code
    } else if (categoryName == 'category2') {
        paymentSource = categoryName +': '+ data.extra.payer +'-'+ data.currency_code 
    } else {
        paymentSource = 'Others'
    }
    
    let transactionDetails = new Transaction(
        data.id,
        data.description,
        categoryName,
        data.made_on,
        data.amount,
        data.currency_code,
        paymentSource)

    transactionArray.push(transactionDetails)
console.log(transactionArray);
}

控制台日志是这样的: [{Transaction1}] [{Transaction1},{Transaction2}] [{Transaction1},{Transaction2},{Transaction3}]

但 UI 的结果仅为 []

在调试期间,我注意到它没有同步读取,所以我尝试使用 readFileSync 但它没有用。我怎样才能同步读取这两个函数,这样它就不会给出一个空数组?

尝试一下以了解 fs 函数在有回调时以及同步时的作用。根据您的代码,我们做了一些更改,这样您就不必使用文件系统库中的同步函数。

首先你需要等待所有的异步任务完成再返回响应。

router.get('/', async (req, res) => {
  // joining path of directory
  const directoryPath = path.join(__dirname, '../data')

  readDirectory(directoryPath).then(() => {
    res.send(JSON.stringify(transactionArray))
  }).catch(err => {
    res.status(500).json(err)
  })
})

其次,为了让代码保持原样以教您一些有关 promise 的知识,让我们将第一个函数包装在 promise 中。

function readDirectory (directoryPath) {
  return new Promise((resolve, reject) => {
    // passsing directoryPath and callback function
    fs.readdir(directoryPath, function (err, files) {
    // handling error
      if (err) {
        return console.log('Unable to scan directory: ' + err)
      }
      // listing all files using map
      const fileSummary = Promise.all(
       files.map(file => {
          return new Promise((resolve, reject) => {
          // get the filename
            let categoryName = ''

            if (file.includes('category1')) {
              categoryName = 'category1'
            } else if (file.includes('category2')) {
              categoryName = 'category2'
            } else {
              categoryName = 'Others'
            }

            // read the file
            const filePath = directoryPath + '/' + file

            fs.readFile(filePath, 'utf8', (err, fileContents) => {
              if (err) {
                console.error(err)
                reject(err)
              }
              try {
                const data = JSON.parse(fileContents, categoryName)
                processFile(data, categoryName).then(data => {
                  data()
                })
              } catch (err) {
                console.error(err)
                reject(err)
              }
            })
          })
        })
      ).then(() => {
        resolve()
      }).catch(err => {
        reject(err)
      })
    })
  })
}

请参考圣经 (MDN) javascript 关于 promises -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

最后将 processFile 函数包装在一个 promise 中

function processFile (data, categoryName) {
  return new Promise((resolve, reject) => {
    let paymentSource = ''

    if (categoryName == 'category1') {
      paymentSource = categoryName + ': ' + categoryName + ' ' + data.currency_code
    } else if (categoryName == 'category2') {
      paymentSource = categoryName + ': ' + data.extra.payer + '-' + data.currency_code
    } else {
      paymentSource = 'Others'
    }

    const transactionDetails = new Transaction(
      data.id,
      data.description,
      categoryName,
      data.made_on,
      data.amount,
      data.currency_code,
      paymentSource)

    transactionArray.push(transactionDetails)
    console.log(transactionArray)
    resolve()
  })
}

我到底在做什么?我只是让您的代码执行异步任务,但在继续之前等待它们完成。 Promises 是处理这个问题的一种方式。您可以使用 FS 同步函数轻松完成此操作,但通过这种方式您可以了解 promises!