【问题标题】:Not awaiting nested promise不等待嵌套的承诺
【发布时间】:2020-04-21 17:16:46
【问题描述】:

应该注意的是,我对所有这些异步的东西都很陌生。

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

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

// 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:": []
}

我做错了什么?

【问题讨论】:

    标签: javascript node.js asynchronous async-await fs


    【解决方案1】:

    你混合了回调和承诺。 fs.writeFile 的回调版本返回 undefined,不幸的是,这是一个值 JavaScript 将非常乐意为您提供 await(根本不需要等待任何东西)。

    使用来自fs Promises APIfs.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))) {
    

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

    forEachasync 操作也总是错误的,因为 forEach 丢弃其操作返回的任何内容,并且异步函数的返回值至关重要。尽管drives 的来源尚不清楚,但您需要一个常规循环才能串行运行:

    for (const value of stdout) {
      // ??
    }
    
    await guaranteeData(drives)
    console.log('should come last')
    // updateData(drives)
    

    最后,detectDriveInfo() 需要一个承诺版本的exec 才能正确解析。现在它返回的 Promise 也不会等待操作完成。

    【讨论】:

    • 为了简化我的 q,我从 forEach/if 块中删除了很多逻辑。伙计,forEachfor/of 方便得多,因为它默认带有index
    • @oldboy:完全不工作真的很方便吗? for (const [i, value] of stdout.entries()).
    • @oldboy:是的。 .entries() 是数组上的一种方法,它返回其 [index, value] 对的迭代器。
    • @oldboy:检查文件是否存在 → 写入文件是一个常见错误,因为在您进行检查之后但在写入文件之前,该文件可以由不同的进程创建。即使这个工具不会发生这种情况,正确的版本也更干净(整个复杂的fs.promises.access 事情,你可以完全摆脱flags: 'wx')。
    【解决方案2】:

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

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

    【讨论】:

    • forEach 非常好,它默认带有idx,我也可以将它与其他所有东西链接在一起。感谢您的意见
    猜你喜欢
    • 2017-04-04
    • 1970-01-01
    • 2018-05-05
    • 1970-01-01
    • 1970-01-01
    • 2018-04-17
    • 2017-04-02
    • 2019-04-29
    • 2019-05-29
    相关资源
    最近更新 更多