不等待嵌套的承诺

Not awaiting nested promise

应该指出的是,我对所有这些异步内容都很陌生。

我试图等到文件的存在得到验证,如果需要,脚本会在更新文件之前创建文件。但是,我似乎不知道该怎么做。

我知道我可以使用 fs.writeFileSync,但我更愿意让它异步,以保证它不会阻止任何用户 activity。

// this is now detectDriveInfo(), the entire function unedited, verbatim
async function detectDriveInfo(){
  const exec = require('child_process').exec
  let
    totalFreespace = 0,
    totalSize = 0,
    drives = []
  exec('wmic logicaldisk get freespace,name,size,volumename', (error, stdout)=>{
    stdout
      .trim()
      .split('\r\r\n')
      .map(value => value.trim().split(/\s{2,}/))
      .slice(1)
      .sort((a,b) => Number(a[0]) - Number(b[0]))
      .forEach(async (value, i, a) => {
        renderDriveInfo(...value)
        totalFreespace += Number(value[0])
        totalSize += Number(value[2])
        drives.push([value[1], Number(value[2]) - Number(value[0])])
        if (i === a.length-1) {
          renderDriveInfo(totalFreespace,'ALL',totalSize,'')
          updateConfigDrives(drives)
          await guaranteeData(drives) // this and its nested promises have to happen/complete
          updateData(drives)          // before this
        }
      })
  })
}

async function guaranteeData(drives){
  const fs = require('fs')
  if (!fs.existsSync('./data.json')) {
    let json = {}
    drives = drives.map(([v]) => v)
    drives.forEach(v => {
      json[v] = []
    })
    json = JSON.stringify(json, null, 2)
    await fs.writeFile('./data.json', json, 'utf8', (error)=>{
      if (error) throw error
      console.log('The file, data.json, has been created.')
      console.log(json)
    })
    return
  }
}

控制台日志

1. should come last
2. The file, data.json, has been created.
3. {
  "C:": [],
  "G:": [],
  "K:": [],
  "D:": [],
  "E:": [],
  "H:": [],
  "J:": [],
  "I:": [],
  "F:": []
}

我做错了什么?

你在混合回调和承诺。 fs.writeFile returns undefined 的回调版本,不幸的是它是一个值 JavaScript 将非常乐意为你 await (通过不等待任何东西全部)。

使用 fs Promises API 中的 fs.promises.writeFile,无回调:

await fs.promises.writeFile('data.json', json, 'utf8')
console.log('The file, data.json, has been created.')
console.log(json)

你可能还想要 specify that the file should never be overwritten,以防它是在存在检查和写入之间创建的:

await fs.promises.writeFile('data.json', json, {
  flag: 'wx',
  encoding: 'utf8',
})

然后使用 fs.existsSync 的非同步等价物:

if (await fs.promises.access('data.json', fs.constants.F_OK)
            .catch(err => err.code === 'ENOENT' || Promise.reject(err))) {

或者完全跳过存在检查并依赖 wx 如果创建 JSON 不是太昂贵。

forEachasync 动作总是错误的,因为 forEach 丢弃任何它的动作 returns,并且 return 的值异步功能至关重要。你需要一个定期循环到 运行 串行,虽然不清楚 drives 来自哪里:

for (const value of stdout) {
  // ??
}

await guaranteeData(drives)
console.log('should come last')
// updateData(drives)

最后,detectDriveInfo() 需要 exec 的承诺版本才能正确解析。现在 promise it returns 也不会等待操作完成。

看到您的代码后,我建议改用现代 for … of 循环,其中 await 将按预期工作:

for (const value of stdout) {
  // Inside this await will work as you aspecting
}