Node.js Express 不等待异步等待

Node.js Express not waiting for Async Await

提问人:Minimuscle 提问时间:7/25/2022 最后编辑:Apoorva ChikaraMinimuscle 更新时间:7/25/2022 访问量:973

问:

我有一个程序正在尝试运行,在获取汽车时,它需要等待函数完成才能运行结果,但它似乎不起作用。我是新手,所以我真的不知道我做得那么好。

app.get('/cars', async (req, res) => {
  try {
    const result = await getCars()
    console.log('result: ' + result)
  res.send(result)
  } catch(error) {
    console.log(error)
  }
  
})

这是调用“getCars”函数的代码,如下所示:

const getCars = async () => {
  // TODO: Replace this with a call to the database
  await fs.readFile(__dirname + '/cars.json', function (err, data) {
    if (err) {
      throw err
    }
    let cars = JSON.parse(data)

    //Groups the cars to their location, to be sorted and chosen based on arrivalDate
    const groupBy = (xs, f) => {
      return xs.reduce(
        (r, v, i, a, k = f(v)) => ((r[k] || (r[k] = [])).push(v), r),
        {}
      )
    }

    const result = groupBy(cars, (c) => c.locationName)

    Object.keys(result).forEach((car) => {
      console.log(car)
      // filters out cars with no arrival dates
      let filtered = result[car].filter(obj => Object.keys(obj).includes("arrivalDate"));

      //Sort cars by the last update time
      filtered.sort(function (a, b) {
        let keyA = new Date(a.arrivalDate.toString().split(' ')[0]),
          keyB = new Date(b.arrivalDate.toString().split(' ')[0])
        // Compare the 2 dates
        if (keyA < keyB) return -1
        if (keyA > keyB) return 1
        return 0
      }).reverse()
      

      //Add the top two (latest) of each car to the new array  
      emailCars = [...emailCars, { [car]: [ result[car][0], result[car][1] ]}]

    })
    console.log('returning' + emailCars)
    return emailCars
  })
}

我在这里缺少什么来确保由函数设置,然后在用户转到 /cars 时发送给用户emailCars

JavaScript node.js 表示 异步等待 回调

评论


答:

2赞 srigi 7/25/2022 #1

我相信问题出在函数的第一行......getCars()

await fs.readFile(__dirname + '/cars.json', function (err, data) {
}

您不能等待在回调中返回结果的函数。使用 readFile 的“sync”版本并从中删除 await/async,或者使用 readFile 的混合版本:getCars()

try {
const data = await fs.promises.readFile(filepath, 'utf8');
} catch (e) {
 // handle errors herer
}

评论

0赞 Minimuscle 7/25/2022
如果我这样做,它会返回所有排序的数据,但我只需要对象中每个子数组的前 2 个(这就是所做的,只获取每个数组中的前 2 个对象)。还是我应该在 /get 函数中执行此操作?emailCars
0赞 aybasaran10 7/25/2022 #2

首先应了解同步/异步概念。这是我的解决方案。

import express from 'express'
import { readFile } from 'fs'
import { dirname } from 'path'
import { fileURLToPath } from 'url'
import { promisify } from 'util'

const app = express()

const readFileAsync = promisify(readFile)

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

const getCars = async () => {
  const file = await readFileAsync(`${__dirname}/cars.json`, 'utf8')
  const cars = JSON.parse(file)

  // DO YOUR LOGIC HERE

  return cars
}

app.get('/', async (req, res) => {
  try {
    const cars = await getCars()
    res.json(cars)
  } catch (error) {
    console.log(error)
  }
})

app.listen(7777, () => {
  console.log('Example app listening on port 7777!')
})
1赞 Apoorva Chikara 7/25/2022 #3

我看到的唯一问题是您将 async/await 与回调概念混合在一起。只需将所有回调替换为 async/await 并将它们包装在 try/catch 周围即可。

const getCars = async () => {
    // TODO: Replace this with a call to the database
    try {
        const data = await fs.readFile(__dirname + '/cars.json') 
            let cars = JSON.parse(data)
        
            //Groups the cars to their location, to be sorted and chosen based on arrivalDate
            const groupBy = (xs, f) => {
              return xs.reduce(
                (r, v, i, a, k = f(v)) => ((r[k] || (r[k] = [])).push(v), r),
                {}
              )
            }
        
            const result = groupBy(cars, (c) => c.locationName)
        
            Object.keys(result).forEach((car) => {
              console.log(car)
              // filters out cars with no arrival dates
              let filtered = result[car].filter(obj => Object.keys(obj).includes("arrivalDate"));
        
              //Sort cars by the last update time
              filtered.sort(function (a, b) {
                let keyA = new Date(a.arrivalDate.toString().split(' ')[0]),
                  keyB = new Date(b.arrivalDate.toString().split(' ')[0])
                // Compare the 2 dates
                if (keyA < keyB) return -1
                if (keyA > keyB) return 1
                return 0
              }).reverse()
              
        
              //Add the top two (latest) of each car to the new array  
              emailCars = [...emailCars, { [car]: [ result[car][0], result[car][1] ]}]
        
            })
            console.log('returning' + emailCars)
            return emailCars
    } catch (e) {
        console.log(e);
    }
    
  }

如果您在理解此概念时遇到任何困难,请查看链接。

如果我这样做,它会返回所有排序的数据,但我只需要 对象中每个子数组的前 2 个(这就是 emailCars 确实,只获取每个数组中的前 2 个对象)。或者我应该做 而不是在 /get 函数中?

任何实用程序函数都应正确组织,以保持应用程序的正确结构。路由不应该包含太多逻辑,逻辑应该放在控制器或类似的东西下。

您需要设计自己的逻辑,如果您遇到任何问题,欢迎您在此平台上提问。

评论

0赞 Minimuscle 7/25/2022
这奏效了,虽然我用了后者,但后者不起作用,但前者起作用了。我以前从未使用过 FS,但我现在更了解它了。谢谢fs.readFileSyncawait fs.readFile
0赞 Apoorva Chikara 7/25/2022
这是因为您需要获取基于 promise 的 fs.readfile,它将按预期工作。将阻止您的后续请求,而您不想要它。readFileSync